Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

OPPIA-1569: Update unzip logic and update permission handling #1327

Merged
merged 1 commit into from
Jun 28, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,14 +1,12 @@
package org.digitalcampus.oppia.activity;

import static android.Manifest.permission.READ_EXTERNAL_STORAGE;

import android.app.Activity;
import android.app.AlertDialog;
import android.content.ClipData;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.database.Cursor;
import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
import android.provider.OpenableColumns;
Expand All @@ -19,13 +17,13 @@

import androidx.activity.result.ActivityResultLauncher;
import androidx.activity.result.contract.ActivityResultContracts;
import androidx.core.app.ActivityCompat;
import androidx.core.content.ContextCompat;
import androidx.annotation.NonNull;

import org.apache.commons.io.IOUtils;
import org.digitalcampus.mobile.learning.R;
import org.digitalcampus.mobile.learning.databinding.ActivityOfflineCourseImportBinding;
import org.digitalcampus.oppia.adapter.OfflineCourseImportAdapter;
import org.digitalcampus.oppia.application.PermissionsManager;
import org.digitalcampus.oppia.exception.CourseInstallException;
import org.digitalcampus.oppia.listener.InstallCourseListener;
import org.digitalcampus.oppia.listener.OnRemoveButtonClickListener;
Expand Down Expand Up @@ -55,7 +53,6 @@

public class OfflineCourseImportActivity extends AppActivity implements InstallCourseListener, ScanMediaListener, OnRemoveButtonClickListener {

private static final int REQUEST_PERMISSION_READ_EXTERNAL_STORAGE = 1;
private ActivityOfflineCourseImportBinding binding;
private OfflineCourseImportAdapter adapter;
private boolean coursesImported = false;
Expand Down Expand Up @@ -104,8 +101,10 @@ public boolean onOptionsItemSelected(MenuItem item) {
}

private void launchFileExplorer() {
if (ContextCompat.checkSelfPermission(this, READ_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {
ActivityCompat.requestPermissions(this, new String[]{READ_EXTERNAL_STORAGE}, REQUEST_PERMISSION_READ_EXTERNAL_STORAGE);
final List<String> notGrantedPerms = PermissionsManager.filterNotGrantedPermissions(
OfflineCourseImportActivity.this, PermissionsManager.OFFLINE_COURSE_IMPORT_PERMISSIONS_REQUIRED);
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.TIRAMISU && !notGrantedPerms.isEmpty()) {
PermissionsManager.requestPermissions(OfflineCourseImportActivity.this, notGrantedPerms);
} else {
Intent intent = new Intent(Intent.ACTION_GET_CONTENT);
intent.addCategory(Intent.CATEGORY_OPENABLE);
Expand All @@ -115,6 +114,12 @@ private void launchFileExplorer() {
}
}

@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
PermissionsManager.onRequestPermissionsResult(this, requestCode, permissions, grantResults);
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
}

private final ActivityResultLauncher<Intent> someActivityResultLauncher = registerForActivityResult(
new ActivityResultContracts.StartActivityForResult(),
result -> {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,24 +19,29 @@

import android.Manifest;
import android.app.Activity;
import android.app.AlertDialog;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.content.pm.PackageManager;
import android.net.Uri;
import android.os.Build;

import androidx.annotation.NonNull;
import androidx.preference.PreferenceManager;

import android.provider.Settings;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;

import androidx.annotation.NonNull;
import androidx.core.app.ActivityCompat;
import androidx.preference.PreferenceManager;

import org.digitalcampus.mobile.learning.R;
import org.digitalcampus.mobile.learning.databinding.ViewPermissionsExplanationBinding;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;

public class PermissionsManager {
Expand All @@ -59,6 +64,10 @@ public class PermissionsManager {
Manifest.permission.POST_NOTIFICATIONS
);

public static final List<String> OFFLINE_COURSE_IMPORT_PERMISSIONS_REQUIRED = Arrays.asList(
Manifest.permission.READ_EXTERNAL_STORAGE
);

public static final int STARTUP_PERMISSIONS = 1;
public static final int BLUETOOTH_PERMISSIONS = 2;
public static final int STORAGE_PERMISSIONS = 3;
Expand All @@ -76,6 +85,14 @@ private static void setAsked(SharedPreferences prefs, String permission) {
prefs.edit().putBoolean(permission + "_asked", true).apply();
}

private static boolean isPermissionDeniedOnce(SharedPreferences prefs, String permission) {
return prefs.getBoolean(permission + "_denied", false);
}

private static void setDenied(SharedPreferences prefs, String permission) {
prefs.edit().putBoolean(permission + "_denied", true).apply();
}

public static boolean checkPermissionsAndInform(final Activity act, int perms) {
ViewGroup container = act.findViewById(R.id.permissions_explanation);
return checkPermissionsAndInform(act, perms, container);
Expand Down Expand Up @@ -151,6 +168,10 @@ private static void showPermissionDescriptions(Context ctx, View container, fina
}
}

public static void requestPermission(final Activity act, String permission) {
requestPermissions(act, Collections.singletonList(permission));
}

public static void requestPermissions(final Activity act, List<String> permissions) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
act.requestPermissions(permissions.toArray(new String[0]), PERMISSIONS_REQUEST);
Expand Down Expand Up @@ -203,15 +224,39 @@ public static boolean onRequestPermissionsResult(Context ctx, int requestCode, S
for (int i = 0; i < permissions.length; i++) {
setAsked(prefs, permissions[i]);

if (grantResults[i] == PackageManager.PERMISSION_GRANTED) {
if (grantResults.length > 0 && grantResults[i] == PackageManager.PERMISSION_GRANTED) {
Log.d("Permissions", "Permission Granted: " + permissions[i]);
permissionsGranted++;
} else if (grantResults[i] == PackageManager.PERMISSION_DENIED) {
} else {
Log.d("Permissions", "Permission Denied: " + permissions[i]);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
if (ActivityCompat.shouldShowRequestPermissionRationale((Activity) ctx, permissions[i])) {
setDenied(prefs, permissions[i]);
} else if (isPermissionDeniedOnce(prefs, permissions[i])) {
showPermissionDeniedDialog(ctx);
}
}
}
}
}
return permissions.length == permissionsGranted;
}

public static void showPermissionDeniedDialog(Context context) {
AlertDialog.Builder builder = new AlertDialog.Builder(context);
builder.setTitle(context.getString(R.string.permissions_denied));
builder.setMessage(context.getString(R.string.permissions_not_askable_message));
builder.setPositiveButton(context.getString(R.string.app_settings), (dialog, which) -> PermissionsManager.openAppSettings(context));
builder.setNegativeButton(context.getString(R.string.cancel), (dialog, which) -> {});

builder.create().show();
}

public static void openAppSettings(Context context) {
Intent intent = new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS);
Uri uri = Uri.fromParts("package", context.getPackageName(), null);
intent.setData(uri);
context.startActivity(intent);
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -87,11 +87,18 @@ public static void unzipFiles(Context context, String srcDirectory, String srcFi

long availableStorage = Storage.getAvailableStorageSize(context);
long uncompressedSize = 0;
try (ZipFile zipFile = new ZipFile(sourceFile)) {
Enumeration<? extends ZipEntry> entries = zipFile.entries();
while (entries.hasMoreElements()) {
ZipEntry zipEntry = entries.nextElement();
uncompressedSize += zipEntry.getSize();
try (ZipInputStream zipInputStream = new ZipInputStream(new FileInputStream(sourceFile))) {
byte[] buffer = new byte[4096];
ZipEntry zipEntry;

while ((zipEntry = zipInputStream.getNextEntry()) != null) {
if (!zipEntry.isDirectory()) {
int bytesRead;
while ((bytesRead = zipInputStream.read(buffer)) != -1) {
uncompressedSize += bytesRead;
}
}
zipInputStream.closeEntry();
}
} catch (IOException e) {
e.printStackTrace();
Expand Down
4 changes: 3 additions & 1 deletion app/src/main/res/values-es/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -280,7 +280,7 @@
<string name="error_preloading_accounts">Error precargando cuentas de usuario desde fichero CSV</string>
<string name="error_reset_password">Nombre de usuario o email no encontrado\nInténtelo de nuevo</string>
<string name="no_title_set">Sin título</string>
h

<string name="info.startup.preloaded_accounts">Precargadas %1$d nueva(s) cuenta(s) de usuario.</string>
<string name="empty_state_media">Genial! Ha descargado todo el contenido multimedia de sus cursos en el dispositivo.</string>
<string name="menu_sort_by">Ordenar por</string>
Expand All @@ -305,6 +305,8 @@
<string name="permissions.bluetooth.message">La app necesita permisos adicionales para buscar otros dispositivos Bluetooth.</string>
<string name="permissions.location.title">acceder a la ubicación</string>
<string name="permissions.location.description">En las últimas versiones de Android se necesita este permiso para poder enlazar otros dispositivos con Bluetooth</string>
<string name="permissions.denied">Permiso denegado</string>
<string name="app_settings">Ajustes de la app</string>

<string name="prefLogoutEnabled">Permitir cierre de sesión desde el menú principal</string>
<string name="register_alert_title">Registro</string>
Expand Down
2 changes: 2 additions & 0 deletions app/src/main/res/values/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -368,6 +368,7 @@
needs the following permissions to function properly:</string>
<string name="permissions.storage.title">Read and modify contents of the SD card</string>
<string name="permissions.simple.title">Permissions needed</string>
<string name="permissions.denied">Permission denied</string>
<string name="permissions.storage.description">&appName; needs access to the SD card to be able to store the downloaded media contents for the courses</string>
<string name="permissions.phone_state.title">read phone state and identity</string>
<string name="permissions.phone_state.description">&appName; needs access to the phone identity to get information about your device model and Android version</string>
Expand All @@ -377,6 +378,7 @@
<string name="permissions.not_askable.info">You see this message because permissions were prompted before and you denied them and checked \"Don\'t ask again\"</string>
<string name="permissions.bluetooth.message">The app needs some additional permissions to scan for Bluetooth devices.</string>
<string name="error_apikey_expired">Your API key expired. Please, log in again.</string>
<string name="app_settings">App Settings</string>

<string name="privacy.title">Privacy and Your Data</string>
<string name="privacy.policy_info">Privacy policy</string>
Expand Down
Loading