Loading app/src/main/java/net/fabiszewski/ulogger/PermissionHelper.java 0 → 100644 +204 −0 Original line number Diff line number Diff line package net.fabiszewski.ulogger; import static android.Manifest.permission.ACCESS_BACKGROUND_LOCATION; import static android.Manifest.permission.ACCESS_COARSE_LOCATION; import static android.Manifest.permission.ACCESS_FINE_LOCATION; import android.Manifest; import android.annotation.SuppressLint; import android.content.Context; import android.content.pm.PackageManager; import android.content.res.Configuration; import android.os.Build; import android.util.Log; import androidx.activity.result.ActivityResultLauncher; import androidx.activity.result.contract.ActivityResultContracts; import androidx.annotation.NonNull; import androidx.annotation.RequiresApi; import androidx.core.app.ActivityCompat; import androidx.core.content.ContextCompat; import androidx.fragment.app.Fragment; import java.util.ArrayList; import java.util.List; import java.util.Locale; import java.util.Map; public class PermissionHelper { public interface PermissionRequester { void onPermissionGranted(String requestCode); void onPermissionDenied(String requestCode); } private static final String TAG = PermissionHelper.class.getSimpleName(); private String requestCode; final ActivityResultLauncher<String[]> resultLauncher; final Fragment fragment; boolean isLocationStageTwoNeeded = false; public PermissionHelper(Fragment fragment, PermissionRequester requester) { this.fragment = fragment; resultLauncher = fragment.registerForActivityResult(new ActivityResultContracts.RequestMultiplePermissions(), results -> { if (Logger.DEBUG) { Log.d(TAG, "[requestPermission: " + results.entrySet() + "]"); } boolean isGranted = false; for (Map.Entry<String, Boolean> result : results.entrySet()) { if (result.getValue()) { isGranted = true; } } boolean isStageTwoNeeded = isLocationStageTwoNeeded; isLocationStageTwoNeeded = false; if (isStageTwoNeeded && isGranted) { if (Logger.DEBUG) { Log.d(TAG, "[PermissionHelper: stage two needed]"); } if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) { requestBackgroundLocationPermission(this.requestCode); } } else if (isGranted) { if (Logger.DEBUG) { Log.d(TAG, "[PermissionHelper: permission granted]"); } requester.onPermissionGranted(this.requestCode); } else { if (Logger.DEBUG) { Log.d(TAG, "[PermissionHelper: permission refused]"); } requester.onPermissionDenied(this.requestCode); } }); } public void requestWritePermission(String requestCode) { requestPermission(Manifest.permission.WRITE_EXTERNAL_STORAGE, requestCode); } @RequiresApi(api = Build.VERSION_CODES.TIRAMISU) public void requestNotificationsPermission(String requestCode) { requestPermission(Manifest.permission.POST_NOTIFICATIONS, requestCode); } public void requestFineLocationPermission(String requestCode) { List<String> permissions = new ArrayList<>(); permissions.add(android.Manifest.permission.ACCESS_FINE_LOCATION); if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) { // On Android 12+ coarse location permission must be also requested permissions.add(ACCESS_COARSE_LOCATION); } requestPermissions(permissions, requestCode); } public void requestCoarseLocationPermission(String requestCode) { requestPermission(android.Manifest.permission.ACCESS_COARSE_LOCATION, requestCode); } @RequiresApi(api = Build.VERSION_CODES.R) public void requestBackgroundLocationPermission(String requestCode) { List<String> permissions = new ArrayList<>(); // Background location permission can only be granted when forward location is permitted if (hasForwardLocationPermission()) { permissions.add(android.Manifest.permission.ACCESS_BACKGROUND_LOCATION); } else { if (Logger.DEBUG) { Log.d(TAG, "[forward location permission denied]"); } permissions.add(android.Manifest.permission.ACCESS_FINE_LOCATION); if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) { // On Android 12+ coarse location permission must be also requested permissions.add(android.Manifest.permission.ACCESS_COARSE_LOCATION); } } if (permissions.contains(android.Manifest.permission.ACCESS_BACKGROUND_LOCATION) && ActivityCompat.shouldShowRequestPermissionRationale(fragment.requireActivity(), android.Manifest.permission.ACCESS_BACKGROUND_LOCATION)) { final CharSequence label = getBackgroundPermissionOptionLabel(fragment.requireContext()); Alert.showConfirm( fragment.requireContext(), fragment.getString(R.string.background_location_required), fragment.getString(R.string.background_location_rationale, label), (dialog, which) -> { dialog.dismiss(); requestPermissions(permissions, requestCode); } ); } else { requestPermissions(permissions, requestCode); } } public void requestPermission(String permission, String requestCode) { List<String> permissions = new ArrayList<>(); permissions.add(permission); requestPermissions(permissions, requestCode); } public void requestPermissions(List<String> permissions, String requestCode) { this.requestCode = requestCode; resultLauncher.launch(permissions.toArray(new String[0])); } public boolean hasPermission(String permission) { Context context = fragment.getContext(); if (context == null) { if (Logger.DEBUG) { Log.d(TAG, "[hasPermission: null context]"); } return false; } return ContextCompat.checkSelfPermission(context, permission) == PackageManager.PERMISSION_GRANTED; } /** * Check if user granted permission to access location. * * @return True if permission granted, false otherwise */ boolean hasForwardLocationPermission() { boolean ret = (ActivityCompat.checkSelfPermission(fragment.requireContext(), Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED) || (ActivityCompat.checkSelfPermission(fragment.requireContext(), Manifest.permission.ACCESS_COARSE_LOCATION) == PackageManager.PERMISSION_GRANTED); if (Logger.DEBUG) { Log.d(TAG, "[hasForwardLocationPermission: " + ret + "]"); } return ret; } /** * Check if user granted permission to access background location. * * @return True if permission granted, false otherwise */ boolean hasBackgroundLocationPermission() { boolean ret = true; if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) { ret = (ActivityCompat.checkSelfPermission(fragment.requireContext(), Manifest.permission.ACCESS_BACKGROUND_LOCATION) == PackageManager.PERMISSION_GRANTED); } if (Logger.DEBUG) { Log.d(TAG, "[hasBackgroundLocationPermission: " + ret + "]"); } return ret; } public static boolean isLocationPermission(@NonNull String permission) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q && ACCESS_BACKGROUND_LOCATION.equals(permission)) { return true; } return ACCESS_COARSE_LOCATION.equals(permission) || ACCESS_FINE_LOCATION.equals(permission); } /** * Wrapper for getBackgroundPermissionOptionLabel() method * Will return translated label only when context string was also translated * @param context Context * @return Localized label */ @SuppressLint("AppBundleLocaleChanges") @RequiresApi(api = Build.VERSION_CODES.R) private CharSequence getBackgroundPermissionOptionLabel(Context context) { CharSequence label = context.getPackageManager().getBackgroundPermissionOptionLabel(); CharSequence defaultLabel = "Allow all the time"; if (Locale.getDefault().getLanguage().equals("en")) { return label.length() > 0 ? label : defaultLabel; } CharSequence translated = context.getString(R.string.background_location_rationale); Configuration config = new Configuration(context.getResources().getConfiguration()); config.setLocale(Locale.ENGLISH); CharSequence defaultText = context.createConfigurationContext(config).getText(R.string.background_location_rationale); return translated.equals(defaultText) ? defaultLabel : label; } } app/src/main/java/net/fabiszewski/ulogger/SelfCheckFragment.java +138 −19 Original line number Diff line number Diff line Loading @@ -15,7 +15,9 @@ import static android.Manifest.permission.ACCESS_FINE_LOCATION; import static android.Manifest.permission.POST_NOTIFICATIONS; import static android.Manifest.permission.WRITE_EXTERNAL_STORAGE; import android.annotation.SuppressLint; import android.content.Context; import android.content.Intent; import android.content.SharedPreferences; import android.content.pm.PackageManager; import android.content.pm.PermissionInfo; Loading @@ -25,28 +27,33 @@ import android.os.Bundle; import android.os.Handler; import android.os.Looper; import android.os.PowerManager; import android.provider.Settings; import android.util.Log; import android.view.LayoutInflater; import android.view.MotionEvent; import android.view.View; import android.view.ViewGroup; import android.widget.TextView; import androidx.activity.result.ActivityResultLauncher; import androidx.activity.result.contract.ActivityResultContracts; import androidx.annotation.NonNull; import androidx.annotation.Nullable; import androidx.annotation.RequiresApi; import androidx.appcompat.widget.SwitchCompat; import androidx.core.app.ActivityCompat; import androidx.fragment.app.Fragment; import androidx.preference.PreferenceManager; import androidx.swiperefreshlayout.widget.SwipeRefreshLayout; import org.json.JSONException; import java.io.IOException; public class SelfCheckFragment extends Fragment { public class SelfCheckFragment extends Fragment implements PermissionHelper.PermissionRequester { private static final String TAG = SelfCheckFragment.class.getSimpleName(); private SwipeRefreshLayout swipe; private SwitchCompat preciseLocationSwitch; private TextView approximateLocationLabel; private SwitchCompat approximateLocationSwitch; Loading @@ -70,15 +77,19 @@ public class SelfCheckFragment extends Fragment { private SwitchCompat validAccountSwitch; private View batteryUsageLayout; private SwitchCompat batteryUsageSwitch; final PermissionHelper permissionHelper; public SelfCheckFragment() { } public SelfCheckFragment() { permissionHelper = new PermissionHelper(this, this); } @Nullable @Override public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { if (Logger.DEBUG) { Log.d(TAG, "[onCreateView]"); } View layout = inflater.inflate(R.layout.fragment_self_check, container, false); swipe = (SwipeRefreshLayout) layout; swipe.setOnRefreshListener(this::selfCheck); approximateLocationSwitch = layout.findViewById(R.id.permissionApproximateLocationResult); approximateLocationLabel = layout.findViewById(R.id.permissionApproximateLocationLabel); preciseLocationSwitch = layout.findViewById(R.id.permissionPreciseLocationResult); Loading Loading @@ -111,20 +122,24 @@ public class SelfCheckFragment extends Fragment { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { checkPermissions(); } checkProviders(); checkServer(); } private void setRefreshing(boolean refreshing) { swipe.setRefreshing(refreshing); } private void checkServer() { SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(requireContext()); String host = prefs.getString(SettingsActivity.KEY_HOST, "").replaceAll("/+$", ""); serverConfiguredSwitch.setChecked(!host.isEmpty()); serverReachableSwitch.setChecked(false); validAccountSwitch.setChecked(false); setupServerSwitch(serverConfiguredSwitch, !host.isEmpty()); setupServerSwitch(serverReachableSwitch, false); setupServerSwitch(validAccountSwitch, false); if (!host.isEmpty()) { setRefreshing(true); Handler handler = new Handler(Looper.getMainLooper()); new Thread(() -> { Loading Loading @@ -161,15 +176,62 @@ public class SelfCheckFragment extends Fragment { validAccountSwitch.setChecked(finalIsValidAccount); }); } handler.post(() -> setRefreshing(false)); }).start(); } else { setRefreshing(false); } } private void setupServerSwitch(SwitchCompat serverSwitch, boolean state) { serverSwitch.setChecked(state); disableSwitch(serverSwitch); serverSwitch.setOnCheckedChangeListener((view, isChecked) -> { if (isChecked) { Intent intent = new Intent(getContext(), SettingsActivity.class); preferencesLauncher.launch(intent); } }); } final ActivityResultLauncher<Intent> preferencesLauncher = registerForActivityResult( new ActivityResultContracts.StartActivityForResult(), result -> checkServer()); final ActivityResultLauncher<Intent> locationSettingsLauncher = registerForActivityResult( new ActivityResultContracts.StartActivityForResult(), result -> { if (Logger.DEBUG) { Log.d(TAG, "[locationSettingsLauncher result: " + result.getResultCode() + "]"); } checkProviders(); }); final ActivityResultLauncher<Intent> batterySettingsLauncher = registerForActivityResult( new ActivityResultContracts.StartActivityForResult(), result -> { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { checkBatteryUsage(); } }); private void checkProviders() { checkProvider(LocationManager.GPS_PROVIDER, locationGpsSwitch); checkProvider(LocationManager.NETWORK_PROVIDER, locationNetSwitch); } private void checkProvider(String provider, SwitchCompat providerSwitch) { LocationManager locationManager = (LocationManager) requireContext().getSystemService(Context.LOCATION_SERVICE); locationGpsSwitch.setChecked(locationManager.isProviderEnabled(LocationManager.GPS_PROVIDER)); locationNetSwitch.setChecked(locationManager.isProviderEnabled(LocationManager.NETWORK_PROVIDER)); boolean isGpsProviderEnabled = locationManager.isProviderEnabled(provider); providerSwitch.setChecked(isGpsProviderEnabled); disableSwitch(providerSwitch); if (!isGpsProviderEnabled) { providerSwitch.setOnCheckedChangeListener((view, isChecked) -> { if (isChecked) { Intent intent = new Intent(Settings.ACTION_LOCATION_SOURCE_SETTINGS); locationSettingsLauncher.launch(intent); } }); } } @RequiresApi(api = Build.VERSION_CODES.M) Loading @@ -191,20 +253,54 @@ public class SelfCheckFragment extends Fragment { checkBatteryUsage(); } @RequiresApi(api = Build.VERSION_CODES.M) private void setItem(@Nullable View layout, @NonNull TextView label, @NonNull SwitchCompat switchCompat, @NonNull String permission) { if (layout != null) { layout.setVisibility(View.VISIBLE); } switchCompat.setChecked(isAllowed(permission)); boolean hasPermission = permissionHelper.hasPermission(permission); switchCompat.setChecked(hasPermission); disableSwitch(switchCompat); label.setText(getPermissionLabel(permission)); if (!hasPermission) { switchCompat.setOnCheckedChangeListener((view, isChecked) -> { if (isChecked) { switch (permission) { case ACCESS_COARSE_LOCATION: permissionHelper.requestFineLocationPermission(null); break; case ACCESS_FINE_LOCATION: permissionHelper.requestCoarseLocationPermission(null); break; case ACCESS_BACKGROUND_LOCATION: if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) { permissionHelper.requestBackgroundLocationPermission(null); } break; case WRITE_EXTERNAL_STORAGE: permissionHelper.requestWritePermission(null); break; case POST_NOTIFICATIONS: if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) { permissionHelper.requestNotificationsPermission(null); } break; } } }); } } @RequiresApi(api = Build.VERSION_CODES.M) private boolean isAllowed(@NonNull String permission) { boolean isAllowed = ActivityCompat.checkSelfPermission(requireContext(), permission) == PackageManager.PERMISSION_GRANTED; if (Logger.DEBUG) { Log.d(TAG, "[isAllowed " + permission + ": " + isAllowed + " ]"); } return isAllowed; @SuppressLint("ClickableViewAccessibility") private void disableSwitch(@NonNull SwitchCompat switchCompat) { switchCompat.setOnTouchListener((view, event) -> { if (switchCompat.isChecked()) { if (event.getAction() == MotionEvent.ACTION_UP) { switchCompat.setChecked(true); } return true; } return false; }); } private CharSequence getPermissionLabel(@NonNull String permission) { Loading @@ -227,8 +323,31 @@ public class SelfCheckFragment extends Fragment { PowerManager pm = (PowerManager) requireContext().getSystemService(Context.POWER_SERVICE); boolean isIgnoringOptimizations = pm.isIgnoringBatteryOptimizations(requireContext().getPackageName()); batteryUsageSwitch.setChecked(isIgnoringOptimizations); disableSwitch(batteryUsageSwitch); if (!isIgnoringOptimizations) { batteryUsageSwitch.setOnCheckedChangeListener((view, isChecked) -> { if (isChecked) { Intent intent = new Intent(Settings.ACTION_IGNORE_BATTERY_OPTIMIZATION_SETTINGS); batterySettingsLauncher.launch(intent); } }); } if (Logger.DEBUG) { Log.d(TAG, "[isIgnoringOptimizations: " + isIgnoringOptimizations + " ]"); } } @Override public void onPermissionGranted(String requestCode) { if (Logger.DEBUG) { Log.d(TAG, "[onPermissionGranted]"); } if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { checkPermissions(); } } @Override public void onPermissionDenied(String requestCode) { if (Logger.DEBUG) { Log.d(TAG, "[onPermissionDenied]"); } if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { checkPermissions(); } } } app/src/main/res/layout/fragment_self_check.xml +425 −394 File changed.Preview size limit exceeded, changes collapsed. Show changes Loading
app/src/main/java/net/fabiszewski/ulogger/PermissionHelper.java 0 → 100644 +204 −0 Original line number Diff line number Diff line package net.fabiszewski.ulogger; import static android.Manifest.permission.ACCESS_BACKGROUND_LOCATION; import static android.Manifest.permission.ACCESS_COARSE_LOCATION; import static android.Manifest.permission.ACCESS_FINE_LOCATION; import android.Manifest; import android.annotation.SuppressLint; import android.content.Context; import android.content.pm.PackageManager; import android.content.res.Configuration; import android.os.Build; import android.util.Log; import androidx.activity.result.ActivityResultLauncher; import androidx.activity.result.contract.ActivityResultContracts; import androidx.annotation.NonNull; import androidx.annotation.RequiresApi; import androidx.core.app.ActivityCompat; import androidx.core.content.ContextCompat; import androidx.fragment.app.Fragment; import java.util.ArrayList; import java.util.List; import java.util.Locale; import java.util.Map; public class PermissionHelper { public interface PermissionRequester { void onPermissionGranted(String requestCode); void onPermissionDenied(String requestCode); } private static final String TAG = PermissionHelper.class.getSimpleName(); private String requestCode; final ActivityResultLauncher<String[]> resultLauncher; final Fragment fragment; boolean isLocationStageTwoNeeded = false; public PermissionHelper(Fragment fragment, PermissionRequester requester) { this.fragment = fragment; resultLauncher = fragment.registerForActivityResult(new ActivityResultContracts.RequestMultiplePermissions(), results -> { if (Logger.DEBUG) { Log.d(TAG, "[requestPermission: " + results.entrySet() + "]"); } boolean isGranted = false; for (Map.Entry<String, Boolean> result : results.entrySet()) { if (result.getValue()) { isGranted = true; } } boolean isStageTwoNeeded = isLocationStageTwoNeeded; isLocationStageTwoNeeded = false; if (isStageTwoNeeded && isGranted) { if (Logger.DEBUG) { Log.d(TAG, "[PermissionHelper: stage two needed]"); } if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) { requestBackgroundLocationPermission(this.requestCode); } } else if (isGranted) { if (Logger.DEBUG) { Log.d(TAG, "[PermissionHelper: permission granted]"); } requester.onPermissionGranted(this.requestCode); } else { if (Logger.DEBUG) { Log.d(TAG, "[PermissionHelper: permission refused]"); } requester.onPermissionDenied(this.requestCode); } }); } public void requestWritePermission(String requestCode) { requestPermission(Manifest.permission.WRITE_EXTERNAL_STORAGE, requestCode); } @RequiresApi(api = Build.VERSION_CODES.TIRAMISU) public void requestNotificationsPermission(String requestCode) { requestPermission(Manifest.permission.POST_NOTIFICATIONS, requestCode); } public void requestFineLocationPermission(String requestCode) { List<String> permissions = new ArrayList<>(); permissions.add(android.Manifest.permission.ACCESS_FINE_LOCATION); if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) { // On Android 12+ coarse location permission must be also requested permissions.add(ACCESS_COARSE_LOCATION); } requestPermissions(permissions, requestCode); } public void requestCoarseLocationPermission(String requestCode) { requestPermission(android.Manifest.permission.ACCESS_COARSE_LOCATION, requestCode); } @RequiresApi(api = Build.VERSION_CODES.R) public void requestBackgroundLocationPermission(String requestCode) { List<String> permissions = new ArrayList<>(); // Background location permission can only be granted when forward location is permitted if (hasForwardLocationPermission()) { permissions.add(android.Manifest.permission.ACCESS_BACKGROUND_LOCATION); } else { if (Logger.DEBUG) { Log.d(TAG, "[forward location permission denied]"); } permissions.add(android.Manifest.permission.ACCESS_FINE_LOCATION); if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) { // On Android 12+ coarse location permission must be also requested permissions.add(android.Manifest.permission.ACCESS_COARSE_LOCATION); } } if (permissions.contains(android.Manifest.permission.ACCESS_BACKGROUND_LOCATION) && ActivityCompat.shouldShowRequestPermissionRationale(fragment.requireActivity(), android.Manifest.permission.ACCESS_BACKGROUND_LOCATION)) { final CharSequence label = getBackgroundPermissionOptionLabel(fragment.requireContext()); Alert.showConfirm( fragment.requireContext(), fragment.getString(R.string.background_location_required), fragment.getString(R.string.background_location_rationale, label), (dialog, which) -> { dialog.dismiss(); requestPermissions(permissions, requestCode); } ); } else { requestPermissions(permissions, requestCode); } } public void requestPermission(String permission, String requestCode) { List<String> permissions = new ArrayList<>(); permissions.add(permission); requestPermissions(permissions, requestCode); } public void requestPermissions(List<String> permissions, String requestCode) { this.requestCode = requestCode; resultLauncher.launch(permissions.toArray(new String[0])); } public boolean hasPermission(String permission) { Context context = fragment.getContext(); if (context == null) { if (Logger.DEBUG) { Log.d(TAG, "[hasPermission: null context]"); } return false; } return ContextCompat.checkSelfPermission(context, permission) == PackageManager.PERMISSION_GRANTED; } /** * Check if user granted permission to access location. * * @return True if permission granted, false otherwise */ boolean hasForwardLocationPermission() { boolean ret = (ActivityCompat.checkSelfPermission(fragment.requireContext(), Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED) || (ActivityCompat.checkSelfPermission(fragment.requireContext(), Manifest.permission.ACCESS_COARSE_LOCATION) == PackageManager.PERMISSION_GRANTED); if (Logger.DEBUG) { Log.d(TAG, "[hasForwardLocationPermission: " + ret + "]"); } return ret; } /** * Check if user granted permission to access background location. * * @return True if permission granted, false otherwise */ boolean hasBackgroundLocationPermission() { boolean ret = true; if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) { ret = (ActivityCompat.checkSelfPermission(fragment.requireContext(), Manifest.permission.ACCESS_BACKGROUND_LOCATION) == PackageManager.PERMISSION_GRANTED); } if (Logger.DEBUG) { Log.d(TAG, "[hasBackgroundLocationPermission: " + ret + "]"); } return ret; } public static boolean isLocationPermission(@NonNull String permission) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q && ACCESS_BACKGROUND_LOCATION.equals(permission)) { return true; } return ACCESS_COARSE_LOCATION.equals(permission) || ACCESS_FINE_LOCATION.equals(permission); } /** * Wrapper for getBackgroundPermissionOptionLabel() method * Will return translated label only when context string was also translated * @param context Context * @return Localized label */ @SuppressLint("AppBundleLocaleChanges") @RequiresApi(api = Build.VERSION_CODES.R) private CharSequence getBackgroundPermissionOptionLabel(Context context) { CharSequence label = context.getPackageManager().getBackgroundPermissionOptionLabel(); CharSequence defaultLabel = "Allow all the time"; if (Locale.getDefault().getLanguage().equals("en")) { return label.length() > 0 ? label : defaultLabel; } CharSequence translated = context.getString(R.string.background_location_rationale); Configuration config = new Configuration(context.getResources().getConfiguration()); config.setLocale(Locale.ENGLISH); CharSequence defaultText = context.createConfigurationContext(config).getText(R.string.background_location_rationale); return translated.equals(defaultText) ? defaultLabel : label; } }
app/src/main/java/net/fabiszewski/ulogger/SelfCheckFragment.java +138 −19 Original line number Diff line number Diff line Loading @@ -15,7 +15,9 @@ import static android.Manifest.permission.ACCESS_FINE_LOCATION; import static android.Manifest.permission.POST_NOTIFICATIONS; import static android.Manifest.permission.WRITE_EXTERNAL_STORAGE; import android.annotation.SuppressLint; import android.content.Context; import android.content.Intent; import android.content.SharedPreferences; import android.content.pm.PackageManager; import android.content.pm.PermissionInfo; Loading @@ -25,28 +27,33 @@ import android.os.Bundle; import android.os.Handler; import android.os.Looper; import android.os.PowerManager; import android.provider.Settings; import android.util.Log; import android.view.LayoutInflater; import android.view.MotionEvent; import android.view.View; import android.view.ViewGroup; import android.widget.TextView; import androidx.activity.result.ActivityResultLauncher; import androidx.activity.result.contract.ActivityResultContracts; import androidx.annotation.NonNull; import androidx.annotation.Nullable; import androidx.annotation.RequiresApi; import androidx.appcompat.widget.SwitchCompat; import androidx.core.app.ActivityCompat; import androidx.fragment.app.Fragment; import androidx.preference.PreferenceManager; import androidx.swiperefreshlayout.widget.SwipeRefreshLayout; import org.json.JSONException; import java.io.IOException; public class SelfCheckFragment extends Fragment { public class SelfCheckFragment extends Fragment implements PermissionHelper.PermissionRequester { private static final String TAG = SelfCheckFragment.class.getSimpleName(); private SwipeRefreshLayout swipe; private SwitchCompat preciseLocationSwitch; private TextView approximateLocationLabel; private SwitchCompat approximateLocationSwitch; Loading @@ -70,15 +77,19 @@ public class SelfCheckFragment extends Fragment { private SwitchCompat validAccountSwitch; private View batteryUsageLayout; private SwitchCompat batteryUsageSwitch; final PermissionHelper permissionHelper; public SelfCheckFragment() { } public SelfCheckFragment() { permissionHelper = new PermissionHelper(this, this); } @Nullable @Override public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { if (Logger.DEBUG) { Log.d(TAG, "[onCreateView]"); } View layout = inflater.inflate(R.layout.fragment_self_check, container, false); swipe = (SwipeRefreshLayout) layout; swipe.setOnRefreshListener(this::selfCheck); approximateLocationSwitch = layout.findViewById(R.id.permissionApproximateLocationResult); approximateLocationLabel = layout.findViewById(R.id.permissionApproximateLocationLabel); preciseLocationSwitch = layout.findViewById(R.id.permissionPreciseLocationResult); Loading Loading @@ -111,20 +122,24 @@ public class SelfCheckFragment extends Fragment { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { checkPermissions(); } checkProviders(); checkServer(); } private void setRefreshing(boolean refreshing) { swipe.setRefreshing(refreshing); } private void checkServer() { SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(requireContext()); String host = prefs.getString(SettingsActivity.KEY_HOST, "").replaceAll("/+$", ""); serverConfiguredSwitch.setChecked(!host.isEmpty()); serverReachableSwitch.setChecked(false); validAccountSwitch.setChecked(false); setupServerSwitch(serverConfiguredSwitch, !host.isEmpty()); setupServerSwitch(serverReachableSwitch, false); setupServerSwitch(validAccountSwitch, false); if (!host.isEmpty()) { setRefreshing(true); Handler handler = new Handler(Looper.getMainLooper()); new Thread(() -> { Loading Loading @@ -161,15 +176,62 @@ public class SelfCheckFragment extends Fragment { validAccountSwitch.setChecked(finalIsValidAccount); }); } handler.post(() -> setRefreshing(false)); }).start(); } else { setRefreshing(false); } } private void setupServerSwitch(SwitchCompat serverSwitch, boolean state) { serverSwitch.setChecked(state); disableSwitch(serverSwitch); serverSwitch.setOnCheckedChangeListener((view, isChecked) -> { if (isChecked) { Intent intent = new Intent(getContext(), SettingsActivity.class); preferencesLauncher.launch(intent); } }); } final ActivityResultLauncher<Intent> preferencesLauncher = registerForActivityResult( new ActivityResultContracts.StartActivityForResult(), result -> checkServer()); final ActivityResultLauncher<Intent> locationSettingsLauncher = registerForActivityResult( new ActivityResultContracts.StartActivityForResult(), result -> { if (Logger.DEBUG) { Log.d(TAG, "[locationSettingsLauncher result: " + result.getResultCode() + "]"); } checkProviders(); }); final ActivityResultLauncher<Intent> batterySettingsLauncher = registerForActivityResult( new ActivityResultContracts.StartActivityForResult(), result -> { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { checkBatteryUsage(); } }); private void checkProviders() { checkProvider(LocationManager.GPS_PROVIDER, locationGpsSwitch); checkProvider(LocationManager.NETWORK_PROVIDER, locationNetSwitch); } private void checkProvider(String provider, SwitchCompat providerSwitch) { LocationManager locationManager = (LocationManager) requireContext().getSystemService(Context.LOCATION_SERVICE); locationGpsSwitch.setChecked(locationManager.isProviderEnabled(LocationManager.GPS_PROVIDER)); locationNetSwitch.setChecked(locationManager.isProviderEnabled(LocationManager.NETWORK_PROVIDER)); boolean isGpsProviderEnabled = locationManager.isProviderEnabled(provider); providerSwitch.setChecked(isGpsProviderEnabled); disableSwitch(providerSwitch); if (!isGpsProviderEnabled) { providerSwitch.setOnCheckedChangeListener((view, isChecked) -> { if (isChecked) { Intent intent = new Intent(Settings.ACTION_LOCATION_SOURCE_SETTINGS); locationSettingsLauncher.launch(intent); } }); } } @RequiresApi(api = Build.VERSION_CODES.M) Loading @@ -191,20 +253,54 @@ public class SelfCheckFragment extends Fragment { checkBatteryUsage(); } @RequiresApi(api = Build.VERSION_CODES.M) private void setItem(@Nullable View layout, @NonNull TextView label, @NonNull SwitchCompat switchCompat, @NonNull String permission) { if (layout != null) { layout.setVisibility(View.VISIBLE); } switchCompat.setChecked(isAllowed(permission)); boolean hasPermission = permissionHelper.hasPermission(permission); switchCompat.setChecked(hasPermission); disableSwitch(switchCompat); label.setText(getPermissionLabel(permission)); if (!hasPermission) { switchCompat.setOnCheckedChangeListener((view, isChecked) -> { if (isChecked) { switch (permission) { case ACCESS_COARSE_LOCATION: permissionHelper.requestFineLocationPermission(null); break; case ACCESS_FINE_LOCATION: permissionHelper.requestCoarseLocationPermission(null); break; case ACCESS_BACKGROUND_LOCATION: if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) { permissionHelper.requestBackgroundLocationPermission(null); } break; case WRITE_EXTERNAL_STORAGE: permissionHelper.requestWritePermission(null); break; case POST_NOTIFICATIONS: if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) { permissionHelper.requestNotificationsPermission(null); } break; } } }); } } @RequiresApi(api = Build.VERSION_CODES.M) private boolean isAllowed(@NonNull String permission) { boolean isAllowed = ActivityCompat.checkSelfPermission(requireContext(), permission) == PackageManager.PERMISSION_GRANTED; if (Logger.DEBUG) { Log.d(TAG, "[isAllowed " + permission + ": " + isAllowed + " ]"); } return isAllowed; @SuppressLint("ClickableViewAccessibility") private void disableSwitch(@NonNull SwitchCompat switchCompat) { switchCompat.setOnTouchListener((view, event) -> { if (switchCompat.isChecked()) { if (event.getAction() == MotionEvent.ACTION_UP) { switchCompat.setChecked(true); } return true; } return false; }); } private CharSequence getPermissionLabel(@NonNull String permission) { Loading @@ -227,8 +323,31 @@ public class SelfCheckFragment extends Fragment { PowerManager pm = (PowerManager) requireContext().getSystemService(Context.POWER_SERVICE); boolean isIgnoringOptimizations = pm.isIgnoringBatteryOptimizations(requireContext().getPackageName()); batteryUsageSwitch.setChecked(isIgnoringOptimizations); disableSwitch(batteryUsageSwitch); if (!isIgnoringOptimizations) { batteryUsageSwitch.setOnCheckedChangeListener((view, isChecked) -> { if (isChecked) { Intent intent = new Intent(Settings.ACTION_IGNORE_BATTERY_OPTIMIZATION_SETTINGS); batterySettingsLauncher.launch(intent); } }); } if (Logger.DEBUG) { Log.d(TAG, "[isIgnoringOptimizations: " + isIgnoringOptimizations + " ]"); } } @Override public void onPermissionGranted(String requestCode) { if (Logger.DEBUG) { Log.d(TAG, "[onPermissionGranted]"); } if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { checkPermissions(); } } @Override public void onPermissionDenied(String requestCode) { if (Logger.DEBUG) { Log.d(TAG, "[onPermissionDenied]"); } if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { checkPermissions(); } } }
app/src/main/res/layout/fragment_self_check.xml +425 −394 File changed.Preview size limit exceeded, changes collapsed. Show changes