Skip to content

Commit

Permalink
Improved recent camera runtime permission code, included videos
Browse files Browse the repository at this point in the history
  • Loading branch information
federicoiosue committed Mar 10, 2024
1 parent dbfc00d commit 58e4b18
Show file tree
Hide file tree
Showing 7 changed files with 63 additions and 74 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@
import org.junit.After;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Rule;


public class BaseAndroidTestCase {
Expand Down Expand Up @@ -96,6 +97,10 @@ public void tearDown() {
}
}

@Rule
public GrantPermissionRule mRuntimePermissionRule = GrantPermissionRule
.grant(android.Manifest.permission.CAMERA);

private static void grantPermissions() {
GrantPermissionRule.grant(ACCESS_COARSE_LOCATION, ACCESS_FINE_LOCATION, READ_EXTERNAL_STORAGE, RECORD_AUDIO);
if (BuildHelper.isBelowOrEqual(VERSION_CODES.Q)) {
Expand Down Expand Up @@ -188,7 +193,7 @@ protected void createCategory(String categoryName) {
* @param clazz utility class to verify.
*/
protected static void assertUtilityClassWellDefined(final Class<?> clazz)
throws NoSuchMethodException, InstantiationException, IllegalAccessException, InvocationTargetException {
throws NoSuchMethodException, InstantiationException, IllegalAccessException {
assertUtilityClassWellDefined(clazz, false, false);
}

Expand Down
1 change: 1 addition & 0 deletions omniNotes/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@
<uses-permission android:name="android.permission.WAKE_LOCK" />
<uses-permission android:name="android.permission.SCHEDULE_EXACT_ALARM" />
<uses-permission android:name="android.permission.POST_NOTIFICATIONS"/>
<uses-permission android:name="android.permission.CAMERA"/>

<uses-feature
android:name="android.hardware.camera"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,9 @@ protected void onResume() {
LogDelegate.d(Prefs.getAll().toString());
}

protected void showToast(int resourceId, int duration) {
showToast(getResources().getString(resourceId), duration);
}

protected void showToast(CharSequence text, int duration) {
if (Prefs.getBoolean("settings_enable_info", true)) {
Expand Down
108 changes: 44 additions & 64 deletions omniNotes/src/main/java/it/feio/android/omninotes/DetailFragment.java
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,12 @@
*/
package it.feio.android.omninotes;

import static android.Manifest.permission.CAMERA;
import static android.content.Context.CLIPBOARD_SERVICE;
import static android.content.Context.LAYOUT_INFLATER_SERVICE;
import static android.content.pm.PackageManager.FEATURE_CAMERA;
import static android.content.pm.PackageManager.PERMISSION_GRANTED;
import static android.widget.Toast.LENGTH_SHORT;
import static androidx.core.view.ViewCompat.animate;
import static it.feio.android.omninotes.BaseActivity.TRANSITION_HORIZONTAL;
import static it.feio.android.omninotes.BaseActivity.TRANSITION_VERTICAL;
Expand Down Expand Up @@ -73,7 +76,6 @@
import android.content.Context;
import android.content.Intent;
import android.content.pm.ActivityInfo;
import android.content.pm.PackageManager;
import android.content.res.Configuration;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
Expand Down Expand Up @@ -112,10 +114,10 @@
import android.widget.CheckBox;
import android.widget.ImageView;
import android.widget.Toast;
import androidx.activity.result.ActivityResultCallback;
import androidx.activity.result.ActivityResultLauncher;
import androidx.activity.result.contract.ActivityResultContracts;
import androidx.core.content.ContextCompat;
import androidx.activity.result.contract.ActivityResultContracts.RequestPermission;
import androidx.core.util.Pair;
import androidx.drawerlayout.widget.DrawerLayout;
import androidx.fragment.app.FragmentTransaction;
Expand All @@ -124,7 +126,6 @@
import com.neopixl.pixlui.components.edittext.EditText;
import com.pixplicity.easyprefs.library.Prefs;
import com.pushbullet.android.extension.MessagingExtension;
import com.tbruyelle.rxpermissions.RxPermissions;

import de.greenrobot.event.EventBus;
import de.keyboardsurfer.android.widget.crouton.Style;
Expand All @@ -135,7 +136,6 @@
import it.feio.android.checklistview.models.ChecklistManager;
import it.feio.android.omninotes.async.AttachmentTask;
import it.feio.android.omninotes.async.bus.NotesUpdatedEvent;
import it.feio.android.omninotes.async.bus.NotificationsGrantedEvent;
import it.feio.android.omninotes.async.bus.PushbulletReplyEvent;
import it.feio.android.omninotes.async.bus.SwitchFragmentEvent;
import it.feio.android.omninotes.async.notes.NoteProcessorDelete;
Expand All @@ -145,6 +145,7 @@
import it.feio.android.omninotes.exceptions.checked.ContentSecurityException;
import it.feio.android.omninotes.exceptions.checked.UnhandledIntentException;
import it.feio.android.omninotes.helpers.AttachmentsHelper;
import it.feio.android.omninotes.helpers.BuildHelper;
import it.feio.android.omninotes.helpers.IntentHelper;
import it.feio.android.omninotes.helpers.LogDelegate;
import it.feio.android.omninotes.helpers.PermissionsHelper;
Expand Down Expand Up @@ -192,7 +193,6 @@
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Calendar;
import java.util.Collections;
import java.util.Date;
import java.util.List;
import org.apache.commons.collections4.CollectionUtils;
Expand Down Expand Up @@ -516,12 +516,12 @@ private void handleIntents() {

// Sub-action is to take a photo
if (IntentChecker.checkAction(i, ACTION_WIDGET_TAKE_PHOTO)) {
checkAndRequestPermissions();
takePhoto();
}
}

if (IntentChecker.checkAction(i, ACTION_FAB_TAKE_PHOTO)) {
checkAndRequestPermissions();
takePhoto();
}

// Handles third party apps requests of sharing
Expand Down Expand Up @@ -830,7 +830,7 @@ private void performAttachmentAction(int attachmentPosition, int i) {
Attachment attachment = mAttachmentAdapter.getItem(attachmentPosition);
Uri shareableAttachmentUri = mainActivity.getShareableAttachmentUri(attachment);
if (shareableAttachmentUri == null) {
Toast.makeText(getActivity(), R.string.error_saving_attachments, Toast.LENGTH_SHORT).show();
Toast.makeText(getActivity(), R.string.error_saving_attachments, LENGTH_SHORT).show();
break;
}
shareIntent.setType(StorageHelper.getMimeType(getAppContext(), attachment.getUri()));
Expand Down Expand Up @@ -1043,7 +1043,7 @@ private boolean goHome() {
// performs a normal onBackPressed instead of returning back to ListActivity
if (!afterSavedReturnsToList) {
if (!TextUtils.isEmpty(exitMessage)) {
mainActivity.showToast(exitMessage, Toast.LENGTH_SHORT);
mainActivity.showToast(exitMessage, LENGTH_SHORT);
}
mainActivity.finish();

Expand Down Expand Up @@ -1325,66 +1325,47 @@ private void takePhoto() {
mainActivity.showMessage(R.string.feature_not_available_on_this_device, ONStyle.ALERT);
return;
}
// Checks for created file validity
File f = StorageHelper.createNewAttachmentFile(mainActivity, MIME_TYPE_IMAGE_EXT);
if (f == null) {
mainActivity.showMessage(R.string.error, ONStyle.ALERT);
return;
}
attachmentUri = Uri.fromFile(f);
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
intent.putExtra(MediaStore.EXTRA_OUTPUT, FileProviderHelper.getFileProvider(f));
startActivityForResult(intent, TAKE_PHOTO);

}

private void checkAndRequestPermissions() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
if (ContextCompat.checkSelfPermission(mainActivity, Manifest.permission.READ_EXTERNAL_STORAGE)
!= PackageManager.PERMISSION_GRANTED) {
// Permission is not granted
requestPermissionLauncher.launch(Manifest.permission.READ_EXTERNAL_STORAGE);

} else {
// Permission already granted
takePhoto();
}
} else {
// Runtime permissions not needed before Marshmallow
takePhoto();
}
PermissionsHelper.requestPermission(getActivity(), CAMERA,
R.string.permission_camera, binding.snackbarPlaceholder, () -> {
// Checks for created file validity
File f = StorageHelper.createNewAttachmentFile(mainActivity, MIME_TYPE_IMAGE_EXT);
if (f == null) {
mainActivity.showMessage(R.string.error, ONStyle.ALERT);
return;
}
attachmentUri = Uri.fromFile(f);
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
intent.putExtra(MediaStore.EXTRA_OUTPUT, FileProviderHelper.getFileProvider(f));
startActivityForResult(intent, TAKE_PHOTO);
});
}
private final ActivityResultLauncher<String> requestPermissionLauncher =
registerForActivityResult(new ActivityResultContracts.RequestPermission(), isGranted -> {
if (isGranted) {
// Permission granted
takePhoto();
} else {
// Permission denied
Toast.makeText(mainActivity,"Permission denied",Toast.LENGTH_SHORT).show();
}
});

private void takeVideo() {
Intent takeVideoIntent = new Intent(MediaStore.ACTION_VIDEO_CAPTURE);
if (!IntentChecker.isAvailable(mainActivity, takeVideoIntent, new String[]{FEATURE_CAMERA})) {
var takeVideoIntent = new Intent(MediaStore.ACTION_VIDEO_CAPTURE);
if (!IntentChecker.isAvailable(mainActivity, takeVideoIntent,
new String[]{FEATURE_CAMERA})) {
mainActivity.showMessage(R.string.feature_not_available_on_this_device, ONStyle.ALERT);
return;
}
// File is stored in custom ON folder to speedup the attachment
File f = StorageHelper.createNewAttachmentFile(mainActivity, MIME_TYPE_VIDEO_EXT);
if (f == null) {
mainActivity.showMessage(R.string.error, ONStyle.ALERT);
return;
}
attachmentUri = Uri.fromFile(f);
takeVideoIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
takeVideoIntent.putExtra(MediaStore.EXTRA_OUTPUT, FileProviderHelper.getFileProvider(f));
String maxVideoSizeStr = "".equals(Prefs.getString("settings_max_video_size", ""))
? "0" : Prefs.getString("settings_max_video_size", "");
long maxVideoSize = parseLong(maxVideoSizeStr) * 1024L * 1024L;
takeVideoIntent.putExtra(MediaStore.EXTRA_SIZE_LIMIT, maxVideoSize);
startActivityForResult(takeVideoIntent, TAKE_VIDEO);

PermissionsHelper.requestPermission(getActivity(), CAMERA,
R.string.permission_camera, binding.snackbarPlaceholder, () -> {
// File is stored in custom ON folder to speedup the attachment
var f = StorageHelper.createNewAttachmentFile(mainActivity, MIME_TYPE_VIDEO_EXT);
if (f == null) {
mainActivity.showMessage(R.string.error, ONStyle.ALERT);
return;
}
attachmentUri = Uri.fromFile(f);
takeVideoIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
takeVideoIntent.putExtra(MediaStore.EXTRA_OUTPUT, FileProviderHelper.getFileProvider(f));
var maxVideoSizeStr = "".equals(Prefs.getString("settings_max_video_size", ""))
? "0" : Prefs.getString("settings_max_video_size", "");
long maxVideoSize = parseLong(maxVideoSizeStr) * 1024L * 1024L;
takeVideoIntent.putExtra(MediaStore.EXTRA_SIZE_LIMIT, maxVideoSize);
startActivityForResult(takeVideoIntent, TAKE_VIDEO);
});
}

private void takeSketch(Attachment attachment) {
Expand Down Expand Up @@ -2331,10 +2312,9 @@ private class AttachmentOnClickListener implements OnClickListener {

@Override
public void onClick(View v) {

switch (v.getId()) {
// Photo from camera
case R.id.camera:
// requestCameraPermission(TAKE_PHOTO);
takePhoto();
break;
case R.id.recording:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,11 +18,11 @@
package it.feio.android.omninotes.helpers;

import static android.Manifest.permission.WRITE_EXTERNAL_STORAGE;
import static android.content.pm.PackageManager.PERMISSION_GRANTED;
import static com.google.android.material.snackbar.BaseTransientBottomBar.LENGTH_INDEFINITE;
import static com.google.android.material.snackbar.BaseTransientBottomBar.LENGTH_LONG;

import android.app.Activity;
import android.content.pm.PackageManager;
import android.os.Build.VERSION_CODES;
import android.view.View;
import androidx.core.app.ActivityCompat;
Expand All @@ -37,16 +37,14 @@
public class PermissionsHelper {

public static void requestPermission(Activity activity, String permission,
int rationaleDescription, View
messageView, OnPermissionRequestedListener onPermissionRequestedListener) {
int rationaleDescription, View messageView, OnPermissionRequestedListener onPermissionRequestedListener) {

if (skipPermissionRequest(permission)) {
onPermissionRequestedListener.onPermissionGranted();
return;
}

if (ContextCompat.checkSelfPermission(activity, permission)
!= PackageManager.PERMISSION_GRANTED) {
if (ContextCompat.checkSelfPermission(activity, permission) != PERMISSION_GRANTED) {

if (ActivityCompat.shouldShowRequestPermissionRationale(activity, permission)) {
Snackbar.make(messageView, rationaleDescription, LENGTH_INDEFINITE)
Expand All @@ -72,13 +70,13 @@ private static void requestPermissionExecute(Activity activity, String permissio
RxPermissions.getInstance(activity)
.request(permission)
.subscribe(granted -> {
if (granted && onPermissionRequestedListener != null) {
if (Boolean.TRUE.equals(granted) && onPermissionRequestedListener != null) {
onPermissionRequestedListener.onPermissionGranted();
} else {
String msg = activity.getString(R.string.permission_not_granted) + ": " + permission;
var msg = activity.getString(R.string.permission_not_granted) + ": " + permission;
Snackbar.make(messageView, msg, LENGTH_LONG).show();
}
});
}

}
}
1 change: 1 addition & 0 deletions omniNotes/src/main/res/raw/changelog.xml
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
changeDate="Mar 8, 2024"
versionName="6.3.2">
<changelogtext>[b]Happy Women Day!![/b]</changelogtext>
<changelogtext>[i]Improved![/i] Ask for camera permission at runtime (thanks to [a href='https://github.com/pratistha-05']Pratistha Sinha[/a] and [a href='https://github.com/akashs056']Akash Subramanian[/a])</changelogtext>
<changelogtext>[i]Improved![/i] When trying to pin a note without notifications permissions enabled a message will be shown</changelogtext>
<changelogtext>[i]Improved![/i] Updated Gradle build tools to 8.3.0</changelogtext>
<changelogtext>[u]Fix[/u] Protected notes are no more searchable nor their tags (from content) will appear anywhere content's secrecy (thanks to [a href='https://github.com/XYIheng']Yiheng Xiong[/a])</changelogtext>
Expand Down
3 changes: 2 additions & 1 deletion omniNotes/src/main/res/values/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -219,8 +219,9 @@
<string name="remove_filter_archived">Show archived notes</string>
<string name="permission_external_storage">Permission to write on external storage is needed to allow backups on public folders</string>
<string name="permission_external_storage_detail_attachment">Permission to read on external storage is needed to allow attaching files from there</string>
<string name="permission_audio_recording">Permission to use microphone is needed to record audio notes</string>
<string name="permission_audio_recording">Permission to use microphone is needed to record audio notes</string>
<string name="permission_coarse_location">Permission to access to location is needed to add position informations to your notes</string>
<string name="permission_camera">Permission to use camera is required to take photos or videos</string>
<string name="permission_not_granted">Permission not granted</string>
<string name="checklist">Checklist</string>
<string name="text_note">Text note</string>
Expand Down

0 comments on commit 58e4b18

Please sign in to comment.