Skip to content

Commit

Permalink
Merge pull request #1327 from DigitalCampus/oppia-1569-offline-media-…
Browse files Browse the repository at this point in the history
…files-not-importing

OPPIA-1569: Update unzip logic and update permission handling
  • Loading branch information
jbc25 committed Jun 28, 2023
2 parents f7b0598 + 4f20d6f commit 2c6cbb4
Show file tree
Hide file tree
Showing 5 changed files with 81 additions and 20 deletions.
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

0 comments on commit 2c6cbb4

Please sign in to comment.