SWADroid/SWADroid/src/main/java/es/ugr/swad/swadroid/modules/downloads/DownloadsManager.java
Amab f45c57b456
Some checks reported errors
continuous-integration/drone/push Build encountered an error
continuous-integration/drone Build is passing
continuous-integration/drone/tag Build is passing
Fix permissions management on document download for Android 10+. Fixes #419 (#421)
## What changes were proposed in this pull request?

* Fix permissions management on document download for Android 10+. Fixes #419

## How was this patch tested?

Manually.

Reviewed-on: #421
Co-authored-by: Amab <juanmi1982@gmail.com>
Co-committed-by: Amab <juanmi1982@gmail.com>
2023-07-08 11:17:21 +02:00

825 lines
30 KiB
Java

/*
* This file is part of SWADroid.
*
* Copyright (C) 2010 Juan Miguel Boyero Corral <juanmi1982@gmail.com>
*
* SWADroid is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* SWADroid is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with SWADroid. If not, see <http://www.gnu.org/licenses/>.
*/
package es.ugr.swad.swadroid.modules.downloads;
import android.Manifest;
import android.app.Activity;
import android.app.AlertDialog;
import android.content.ActivityNotFoundException;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.content.res.Resources;
import android.graphics.Typeface;
import android.os.Build;
import android.os.Bundle;
import android.os.Environment;
import android.util.Log;
import android.view.KeyEvent;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.AdapterView.OnItemSelectedListener;
import android.widget.ArrayAdapter;
import android.widget.GridView;
import android.widget.Spinner;
import android.widget.TextView;
import android.widget.Toast;
import androidx.annotation.NonNull;
import androidx.core.app.ActivityCompat;
import androidx.core.content.ContextCompat;
import androidx.core.content.FileProvider;
import java.io.File;
import java.net.URLConnection;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import es.ugr.swad.swadroid.Constants;
import es.ugr.swad.swadroid.R;
import es.ugr.swad.swadroid.gui.FontManager;
import es.ugr.swad.swadroid.gui.MenuActivity;
import es.ugr.swad.swadroid.gui.ProgressScreen;
import es.ugr.swad.swadroid.model.Group;
import es.ugr.swad.swadroid.model.GroupType;
import es.ugr.swad.swadroid.modules.courses.Courses;
import es.ugr.swad.swadroid.modules.groups.GroupTypes;
import es.ugr.swad.swadroid.modules.groups.Groups;
import es.ugr.swad.swadroid.modules.login.Login;
import es.ugr.swad.swadroid.modules.marks.GetMarks;
import es.ugr.swad.swadroid.modules.marks.Marks;
import es.ugr.swad.swadroid.utils.Utils;
/**
* Activity to navigate through the directory tree of documents and to manage
* the downloads of documents
*
* @author Helena Rodriguez Gijon <hrgijon@gmail.com>
* @author Juan Miguel Boyero Corral <juanmi1982@gmail.com>
*/
public class DownloadsManager extends MenuActivity {
/**
* Class that contains the directory tree and gives information of each
* level
*/
private DirectoryNavigator navigator;
/**
* Specifies whether to display the documents or the shared area of the
* subject 1 specifies documents area, 2 specifies shared area,
* 3 specifies marks area
*/
private int downloadsAreaCode = 0;
/**
* Specifies chosen group to show its documents
* 0 -
*/
private long chosenGroupCode = 0;
/**
* String that contains the xml files recevied from the web service
*/
private String tree = null;
/**
* Downloads tag name for Logcat
*/
private static final String TAG = Constants.APP_TAG + " Downloads";
/**
* List of group of the selected course to which the user belongs
*/
private List<Group> myGroups;
/**
* Indicates if the groups has been requested
*/
private boolean groupsRequested = false;
/**
* Indicates whether the refresh button was pressed
*/
private boolean refresh = false;
private TextView messageText;
private GridView grid;
private TextView currentPathText;
private ProgressScreen mProgressScreen;
private static Typeface iconFont;
private String chosenNodeName = null;
/**
* fileSize stores the size of the last file name chosen to be downloaded
*/
private long fileSize = 0;
/**
* Indicates the selected position in the groups spinner
* by default the whole course is selected
*/
private int groupPosition = 0;
/**
* Indicates if the menu no connection is visible
*/
private boolean messageView = false;
/**
* Indicates that the current state should be saved in case the activity is brought to background
*/
private boolean saveState = false;
/**
* Indicates if the state before the activity was brought to background has o not connection
*/
private boolean previousConnection = false;
private void init() {
mProgressScreen.show();
List<Group> allGroups = dbHelper.getGroups(Courses.getSelectedCourseCode());
int nGroups = allGroups.size();
if (!saveState) {
if (nGroups != 0 || groupsRequested) { //groupsRequested is used to avoid continue requests of groups on courses that have not any group.
myGroups = getFilteredGroups(); //only groups where the user is enrolled.
int nMyGroups = myGroups.size();
this.loadGroupsSpinner(myGroups);
// the tree request must be explicit only when there are not any groups(where the user is enrolled), and therefore any Spinner.
//in case there are groups(where the user is enrolled), it will be a spinner, and the tree request will be automatic made by OnItemSelectedListener
if (nMyGroups == 0 && tree == null)
requestDirectoryTree();
} else {
Intent activity = new Intent(this, GroupTypes.class);
activity.putExtra("courseCode", Courses.getSelectedCourseCode());
startActivityForResult(activity, Constants.GROUPTYPES_REQUEST_CODE);
}
} else {
myGroups = getFilteredGroups();
this.loadGroupsSpinner(myGroups);
this.previousConnection = Utils.connectionAvailable(getApplicationContext());
if (previousConnection) {
setMainView();
} else {
setNoConnectionView();
}
}
}
@Override
protected void onStart() {
super.onStart();
// check permissions
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.Q
&& ContextCompat.checkSelfPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE)
!= PackageManager.PERMISSION_GRANTED) {
ActivityCompat.requestPermissions(this,
new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE},
Constants.PERMISSIONS_REQUEST_WRITE_EXTERNAL_STORAGE);
} else {
init();
}
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (savedInstanceState != null) {
this.saveState = savedInstanceState.getBoolean("saveState", false);
if (saveState) {
this.groupsRequested = true;
this.previousConnection = savedInstanceState.getBoolean("previousConnection", false);
this.chosenGroupCode = savedInstanceState.getLong("chosenGroupCode", 0);
this.groupPosition = savedInstanceState.getInt("groupPosition", 0);
if (previousConnection) {
this.tree = savedInstanceState.getString("tree");
String path = savedInstanceState.getString("path");
this.navigator = new DirectoryNavigator(getApplicationContext(), this.tree);
if ("/".equals(path)) {
int firstBar = path.indexOf('/', 0);
int nextBar = path.indexOf('/', firstBar + 1);
while (nextBar != -1) {
String dir = path.substring(firstBar + 1, nextBar);
this.navigator.goToSubDirectory(dir);
firstBar = nextBar;
nextBar = path.indexOf('/', firstBar + 1);
}
}
}
}
}
setContentView(R.layout.navigation);
//Get Font Awesome typeface
iconFont = FontManager.getTypeface(this, FontManager.FONTAWESOME);
TextView homeButton = (TextView) this
.findViewById(R.id.home_button);
homeButton.setOnClickListener((v -> {
if (navigator != null) {
updateView(navigator.goToRoot());
}
}));
TextView parentButton = (TextView) this
.findViewById(R.id.parent_button);
parentButton.setOnClickListener((v -> {
if (navigator != null) {
updateView(navigator.goToParentDirectory());
}
}));
//Set Font Awesome typeface
homeButton.setTypeface(iconFont);
parentButton.setTypeface(iconFont);
downloadsAreaCode = getIntent().getIntExtra("downloadsAreaCode",
Constants.DOCUMENTS_AREA_CODE);
messageText = (TextView) this.findViewById(R.id.messageText);
grid = (GridView) this.findViewById(R.id.gridview);
grid.setOnItemClickListener(((parent, v, position, id) -> {
DirectoryItem node = navigator.getDirectoryItem(position);
if (node.getFileCode() == -1) //it is a directory therefore navigates into it
updateView(navigator.goToSubDirectory(position));
else { //it is a files therefore gets its information through web service GETFILE
chosenNodeName = node.getName();
fileSize = node.getSize();
File f = new File(Constants.DOWNLOADS_PATH + File.separator + chosenNodeName);
//If a student is requesting the marks, gets the marks and call the Marks module
if((downloadsAreaCode == Constants.MARKS_AREA_CODE)
&& (Login.getLoggedUser().getUserRole() == Constants.STUDENT_TYPE_CODE)) {
requestGetMarks(node.getFileCode());
} else { //Otherwise treat as a regular file
if (isDownloaded(f)) {
viewFile(f);
} else {
AlertDialog fileInfoDialog = createFileInfoDialog(node.getName(), node.getSize(), node.getTime(), node.getPublisher(), node.getFileCode(), node.getLicense());
fileInfoDialog.show();
}
}
}
}));
View mDirectoryNavigatorView = findViewById(R.id.directoryNavigator);
View mProgressScreenView = findViewById(R.id.progress_screen);
mProgressScreen = new ProgressScreen(mProgressScreenView, mDirectoryNavigatorView,
getString(R.string.loadingMsg), this);
setupActionBar();
}
@Override
public void onBackPressed() {
if ((navigator != null) && (!navigator.isRootDirectory())) {
//If current directory is not the root, go to parent directory
updateView(navigator.goToParentDirectory());
} else {
//If current directory is the root, exit module
super.onBackPressed();
}
}
@Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
//If back button is pressed, go to parent directory
if ((keyCode == KeyEvent.KEYCODE_BACK)) {
if (navigator != null) {
//If current directory is not the root, go to parent directory
if (!navigator.isRootDirectory()) {
updateView(navigator.goToParentDirectory());
//If current directory is the root, exit module
} else {
return super.onKeyDown(keyCode, event);
}
}
return true;
}
return super.onKeyDown(keyCode, event);
}
@Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
outState.putBoolean("saveState", this.saveState);
if (this.saveState) {
outState.putBoolean("previousConnection", this.previousConnection);
outState.putLong("chosenGroupCode", this.chosenGroupCode);
outState.putInt("groupPosition", this.groupPosition);
if (this.previousConnection) {
outState.putString("tree", this.tree);
outState.putString("path", this.navigator.getPath());
}
}
}
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (resultCode == Activity.RESULT_OK) {
Intent activity;
switch (requestCode) {
// After get the list of courses, a dialog is launched to choice the
// course
case Constants.DIRECTORY_TREE_REQUEST_CODE:
tree = data.getStringExtra("tree");
if(refresh && !messageView) {
refresh();
refresh = false;
}
setMainView();
break;
case Constants.GETFILE_REQUEST_CODE:
//if the sd card is not busy, the file can be downloaded
if (this.checkMediaAvailability() == 2) {
Log.i(TAG, "External storage is available");
String url = data.getExtras().getString("link");
downloadFile(Constants.DIRECTORY_SWADROID, url, fileSize);
} else { //if the sd card is busy, it shows a alert dialog
Log.i(TAG, "External storage is NOT available");
AlertDialog.Builder builder = new AlertDialog.Builder(this);
AlertDialog dialog;
builder.setTitle(R.string.sdCardBusyTitle);
builder.setMessage(R.string.sdCardBusy);
builder.setIcon(R.drawable.ic_dialog_alert);
builder.setNeutralButton(android.R.string.ok, new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int id) {
dialog.dismiss();
}
});
dialog = builder.create();
dialog.show();
}
break;
case Constants.GETMARKS_REQUEST_CODE:
activity = new Intent(this, Marks.class);
activity.putExtra("content", GetMarks.getMarks());
startActivityForResult(activity, Constants.MARKS_REQUEST_CODE);
break;
case Constants.GROUPS_REQUEST_CODE:
groupsRequested = true;
myGroups = getFilteredGroups(); //only groups where the user is enrolled.
this.loadGroupsSpinner(myGroups);
if (myGroups.size() == 0) {
requestDirectoryTree();
} else {
mProgressScreen.hide();
}
break;
case Constants.GROUPTYPES_REQUEST_CODE:
activity = new Intent(this, Groups.class);
activity.putExtra("courseCode", Courses.getSelectedCourseCode());
startActivityForResult(activity, Constants.GROUPS_REQUEST_CODE);
break;
}
} else {
if (refresh) {
refresh = false;
}
mProgressScreen.hide();
}
}
/**
* Having connection is mandatory for the Download Module.
* Therefore when there is not connection, the grid of nodes is disabled and instead it is showed an info messages
*/
private void setNoConnectionView() {
getSupportActionBar().setSubtitle(Courses.getSelectedCourseShortName());
this.saveState = true;
this.previousConnection = false;
mProgressScreen.hide();
messageView = true;
messageText.setText(R.string.noConnectionMsg);
messageText.setVisibility(View.VISIBLE);
grid.setVisibility(View.GONE);
this.findViewById(R.id.groupSpinner).setVisibility(View.GONE);
}
/**
* Documents:
*
* Show a warning on Documents screen if there are no documents currently available.
*
* Marks:
*
* Show a warning on Marks screen if student ID has not yet been verified by the teacher or
* there are no marks currently available.
*/
private void setNoDocumentsView() {
int resNoDocuments;
if(downloadsAreaCode == Constants.MARKS_AREA_CODE) {
if (Login.getCurrentUserRole() == Constants.STUDENT_TYPE_CODE)
resNoDocuments = R.string.noMarksStudentMsg;
else {
resNoDocuments = R.string.noMarksTeacherMsg;
}
} else {
resNoDocuments = R.string.noDocumentsMsg;
}
this.findViewById(R.id.groupSpinner).setVisibility(View.GONE);
getSupportActionBar().setSubtitle(Courses.getSelectedCourseShortName());
this.saveState = true;
this.previousConnection = true;
grid.setVisibility(View.GONE);
mProgressScreen.hide();
messageText.setText(resNoDocuments);
messageText.setVisibility(View.VISIBLE);
messageView = true;
}
/**
* This method set the grid of nodes visible and paints the directory tree in its root node
*/
private void setMainView() {
currentPathText = (TextView) this.findViewById(R.id.path);
ArrayList<DirectoryItem> items;
if (!(this.saveState && this.previousConnection)) {
navigator = new DirectoryNavigator(getApplicationContext(), tree);
items = navigator
.goToRoot();
} else {
items = navigator.goToCurrentDirectory();
}
if(items.isEmpty()) {
setNoDocumentsView();
} else {
messageView = false;
messageText.setVisibility(View.GONE);
mProgressScreen.hide();
currentPathText.setText(navigator.getPath());
grid.setAdapter(new NodeAdapter(this, items));
grid.setVisibility(View.VISIBLE);
}
//this is used for the activity restart in case it was taken background
this.saveState = true;
this.previousConnection = true;
}
/**
* This method is called after the new file tree is received when the refresh button is pressed
*/
private void refresh() {
if (navigator != null) {
navigator.refresh(tree);
}
}
/**
* When the user moves into a new directory, this method updates the set of new directories and files and paints it
*/
private void updateView(ArrayList<DirectoryItem> items) {
if(!items.isEmpty()) {
currentPathText.setText(navigator.getPath());
((NodeAdapter) grid.getAdapter()).change(items);
}
}
/**
* Get the list of the groups of the course with a documents zone to whom the user belongs
*/
private List<Group> getFilteredGroups() {
List<Group> currentGroups = dbHelper.getGroups(Courses.getSelectedCourseCode());
//remove groups that do not have a file zone assigned
int j = 0;
while (j < currentGroups.size()) {
if (currentGroups.get(j).getDocumentsArea() != 0 && currentGroups.get(j).isMember())
++j;
else
currentGroups.remove(j);
}
return currentGroups;
}
/**
* If there are not groups to which the user belong in the database, it makes the request
*/
private void loadGroupsSpinner(List<Group> currentGroups) {
if (!currentGroups.isEmpty()) { //there are groups in the selected course, therefore the groups spinner should be loaded
Spinner groupsSpinner = (Spinner) this.findViewById(R.id.groupSpinner);
groupsSpinner.setVisibility(View.VISIBLE);
ArrayList<String> spinnerNames = new ArrayList<>(currentGroups.size() + 1);
spinnerNames.add(getString(R.string.course) + "-" + Courses.getSelectedCourseShortName());
for (Group g : currentGroups) {
GroupType gType = dbHelper.getGroupTypeFromGroup(g.getId());
spinnerNames.add(getString(R.string.group) + "-" + gType.getGroupTypeName() + " " + g.getGroupName());
}
ArrayAdapter<String> adapter = new ArrayAdapter<>(this, android.R.layout.simple_spinner_item, spinnerNames);
adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
groupsSpinner.setAdapter(adapter);
groupsSpinner.setOnItemSelectedListener(new onGroupSelectedListener());
groupsSpinner.setSelection(groupPosition);
} else {
this.findViewById(R.id.groupSpinner).setVisibility(View.GONE);
getSupportActionBar().setSubtitle(Courses.getSelectedCourseShortName());
}
}
/**
* Listener associated with the spinner. With a new group / course is selected, it is requested the right file tree
*/
private class onGroupSelectedListener implements OnItemSelectedListener {
@Override
public void onItemSelected(AdapterView<?> parent, View view, int position,
long id) {
//if the position is 0, it is chosen the whole course. Otherwise a group has been chosen
//position - 0 belongs to the whole course
long newGroupCode = position == 0 ? 0 : myGroups.get(position - 1).getId();
if (chosenGroupCode != newGroupCode || tree == null) {
chosenGroupCode = newGroupCode;
groupPosition = position;
requestDirectoryTree();
}
}
@Override
public void onNothingSelected(AdapterView<?> arg0) {
}
}
/**
* Method to request files tree to SWAD thought the web services GETDIRECTORYTREE
*/
private void requestDirectoryTree() {
Intent activity;
activity = new Intent(this, DirectoryTreeDownload.class);
activity.putExtra("treeCode", downloadsAreaCode);
activity.putExtra("groupCode", (int) chosenGroupCode);
startActivityForResult(activity, Constants.DIRECTORY_TREE_REQUEST_CODE);
}
/**
* It checks if the external storage is available
*
* @return 0 - if external storage can not be read either wrote <br/>
* 1 - if external storage can only be read <br/>
* 2 - if external storage can be read and wrote <br/>
*/
private int checkMediaAvailability() {
String state = Environment.getExternalStorageState();
int returnValue;
if (Environment.MEDIA_MOUNTED.equals(state)) {
// We can read and write the media
returnValue = 2;
} else if (Environment.MEDIA_MOUNTED_READ_ONLY.equals(state)) {
// We can only read the media
returnValue = 1;
} else {
// Something else is wrong. It may be one of many other states, but all we need
// to know is we can neither read nor write
returnValue = 0;
}
return returnValue;
}
/**
* Check if a file is already downloaded or not
* @param f File to check
* @return False if not downloaded, True otherwise.
*/
private boolean isDownloaded(File f) {
return f.exists() && f.length() == fileSize;
}
/**
* Start an intent to view the file
* @param f The file to view.
*/
private void viewFile(File f) {
String mime = URLConnection.guessContentTypeFromName(f.getAbsolutePath());
String authority = "es.ugr.swad.swadroid.fileprovider";
Intent viewFileIntent = new Intent();
try {
viewFileIntent.setAction(Intent.ACTION_VIEW);
viewFileIntent.setDataAndType(FileProvider.getUriForFile(this, authority, f), mime);
viewFileIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
startActivity(viewFileIntent);
} catch (ActivityNotFoundException e) {
showDialog(R.string.errorMsgExecutionOperation, R.string.errorNoAppForIntent);
}
}
/**
* it initializes the download the file from the url @a url and stores it in the directory name @directory
*
* @param directory - directory where the downloaded file will be stored
* @param url - url from which the file is downloaded
* @param fileSize - file size of the file. It is used to show the download progress in the notification
*/
private void downloadFile(String directory, String url, long fileSize) {
// Check if external storage is available
int storageState = checkMediaAvailability();
if (storageState == 2) {
new FileDownloaderAsyncTask(this, this.chosenNodeName)
.execute(directory, url);
} else {
Toast.makeText(this, R.string.sdCardBusyTitle, Toast.LENGTH_LONG).show();
}
}
/**
* Method to request info file identified with @a fileCode to SWAD thought the web services GETFILE
*
* @param fileCode file code
*/
private void requestGetFile(long fileCode) {
Intent activity;
activity = new Intent(this, GetFile.class);
activity.putExtra("fileCode", fileCode);
startActivityForResult(activity, Constants.GETFILE_REQUEST_CODE);
}
/**
* Method to request info file identified with @a fileCode to SWAD thought the web services GETMARKS
*
* @param fileCode file code
*/
private void requestGetMarks(long fileCode) {
Intent activity;
activity = new Intent(this, GetMarks.class);
activity.putExtra("fileCode", fileCode);
startActivityForResult(activity, Constants.GETMARKS_REQUEST_CODE);
}
/**
* Method that shows information file and allows its download
* It has a button to confirm the download. If It is confirmed getFile will be requested to get the link
*/
private AlertDialog createFileInfoDialog(String name, long size, long time, String uploader,
long fileCode, String license) {
AlertDialog.Builder builder = new AlertDialog.Builder(this);
AlertDialog dialog;
final long code = fileCode;
this.fileSize = size;
Date d = new Date(time * 1000);
java.text.DateFormat dateShortFormat = android.text.format.DateFormat.getDateFormat(this);
java.text.DateFormat timeFormat = android.text.format.DateFormat.getTimeFormat(this);
String uploaderName;
if (uploader.compareTo("") != 0)
uploaderName = uploader;
else
uploaderName = this.getResources().getString(R.string.unknown);
StringBuilder message;
Resources res = getResources();
message = new StringBuilder(res.getString(R.string.fileTitle))
.append(" ")
.append(name)
.append("\n")
.append(getString(R.string.sizeFileTitle))
.append(" ")
.append(DownloadFactory.humanReadableByteCount(size, true))
.append("\n")
.append(res.getString(R.string.uploaderTitle))
.append(" ")
.append(uploaderName)
.append("\n")
.append(res.getString(R.string.licenseType))
.append(" ")
.append(license)
.append("\n")
.append(res.getString(R.string.creationTimeTitle))
.append(" ")
.append(dateShortFormat.format(d))
.append(" ")
.append(timeFormat.format(d));
builder.setTitle(name);
builder.setMessage(message);
builder.setPositiveButton(R.string.downloadFileTitle, new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int id) {
requestGetFile(code);
}
});
builder.setNegativeButton(R.string.cancelMsg, new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int id) {
dialog.dismiss();
}
});
dialog = builder.create();
return dialog;
}
/**
* Launches an action when refresh button is pushed.
* <p/>
* The listener onClick is set in action_bar.xml
*
* @param v Actual view
*/
public void onRefreshClick(View v) {
refresh = true;
Intent activity = new Intent(this, GroupTypes.class);
activity.putExtra("courseCode", Courses.getSelectedCourseCode());
startActivityForResult(activity, Constants.GROUPTYPES_REQUEST_CODE);
}
/**
* Set up the {@link android.app.ActionBar}, if the API is available.
*/
private void setupActionBar() {
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
switch (downloadsAreaCode) {
case Constants.DOCUMENTS_AREA_CODE:
setTitle(R.string.documentsDownloadModuleLabel);
break;
case Constants.SHARE_AREA_CODE:
setTitle(R.string.sharedsDownloadModuleLabel);
break;
case Constants.MARKS_AREA_CODE:
setTitle(R.string.marksModuleLabel);
break;
}
}
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions,
@NonNull int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
switch (requestCode) {
case Constants.PERMISSIONS_REQUEST_WRITE_EXTERNAL_STORAGE: {
if (grantResults.length > 0
&& grantResults[0] == PackageManager.PERMISSION_GRANTED) {
init();
} else {
setResult(Activity.RESULT_CANCELED);
finish();
}
}
}
}
}