mirror of
https://github.com/gsantner/dandelion
synced 2024-12-22 19:08:03 +01:00
Update opoc and it's license headers
This commit is contained in:
parent
1129f1848a
commit
2289c04f0f
11 changed files with 381 additions and 56 deletions
|
@ -93,8 +93,8 @@ public class SimpleMarkdownParser {
|
|||
.replaceAll("!\\[(.*?)\\]\\((.*?)\\)", "<img src=\\'$2\\' alt='$1' />") // img
|
||||
.replaceAll("<(http|https):\\/\\/(.*)>", "<a href='$1://$2'>$1://$2</a>") // a href (DEP: img)
|
||||
.replaceAll("\\[(.*?)\\]\\((.*?)\\)", "<a href=\\'$2\\'>$1</a>") // a href (DEP: img)
|
||||
.replaceAll("(?m)^([-*] )(.*)$", "<font color='#000001'>•</font> $2 ") // unordered list + end line
|
||||
.replaceAll("(?m)^ (-|\\*) ([^<]*)$", " <font color='#000001'>•</font> $2 ") // unordered list2 + end line
|
||||
.replaceAll("(?m)^[-*] (.*)$", "<font color='#000001'>•</font> $1 ") // unordered list + end line
|
||||
.replaceAll("(?m)^ [-*] (.*)$", " <font color='#000001'>•</font> $1 ") // unordered list2 + end line
|
||||
.replaceAll("`([^<]*)`", "<code>$1</code>") // code
|
||||
.replace("\\*", "●") // temporary replace escaped star symbol
|
||||
.replaceAll("(?m)\\*\\*(.*)\\*\\*", "<b>$1</b>") // bold (DEP: temp star)
|
||||
|
@ -111,6 +111,7 @@ public class SimpleMarkdownParser {
|
|||
public String filter(String text) {
|
||||
text = text
|
||||
.replace("New:", "<font color='#276230'>New:</font>")
|
||||
.replace("New features:", "<font color='#276230'>New:</font>")
|
||||
.replace("Added:", "<font color='#276230'>Added:</font>")
|
||||
.replace("Add:", "<font color='#276230'>Add:</font>")
|
||||
.replace("Fixed:", "<font color='#005688'>Fixed:</font>")
|
||||
|
|
|
@ -44,6 +44,7 @@ import android.text.TextUtils;
|
|||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Calendar;
|
||||
import java.util.List;
|
||||
|
||||
|
||||
|
@ -512,4 +513,15 @@ public class SharedPreferencesPropertyBackend implements PropertyBackend<String,
|
|||
setStringListOne(key, value, _prefApp);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* A method to determine if current hour is between begin and end.
|
||||
* This is especially useful for time-based light/dark mode
|
||||
*/
|
||||
public boolean isCurrentHourOfDayBetween(int begin, int end) {
|
||||
begin = (begin >= 23 || begin < 0) ? 0 : begin;
|
||||
end = (end >= 23 || end < 0) ? 0 : end;
|
||||
int h = Calendar.getInstance().get(Calendar.HOUR_OF_DAY);
|
||||
return h >= begin && h <= end;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -11,6 +11,7 @@
|
|||
package net.gsantner.opoc.ui;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.graphics.Typeface;
|
||||
import android.support.annotation.ColorInt;
|
||||
import android.support.annotation.NonNull;
|
||||
import android.support.annotation.Nullable;
|
||||
|
@ -23,6 +24,7 @@ import android.text.TextWatcher;
|
|||
import android.view.KeyEvent;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.view.WindowManager;
|
||||
import android.widget.ArrayAdapter;
|
||||
import android.widget.Filter;
|
||||
import android.widget.LinearLayout;
|
||||
|
@ -76,10 +78,10 @@ public class SearchOrCustomTextDialog {
|
|||
TextView textView = (TextView) super.getView(pos, convertView, parent);
|
||||
String text = textView.getText().toString();
|
||||
|
||||
textView.setTextColor(dopt.textColor);
|
||||
if (dopt.highlightData.contains(text)) {
|
||||
textView.setTextColor(dopt.highlightColor);
|
||||
}
|
||||
boolean hl = dopt.highlightData.contains(text);
|
||||
textView.setTextColor(hl ? dopt.highlightColor : dopt.textColor);
|
||||
textView.setTypeface(null, hl ? Typeface.BOLD : Typeface.NORMAL);
|
||||
|
||||
return textView;
|
||||
}
|
||||
|
||||
|
@ -184,6 +186,9 @@ public class SearchOrCustomTextDialog {
|
|||
return false;
|
||||
});
|
||||
|
||||
if (dialog.getWindow() != null) {
|
||||
dialog.getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE);
|
||||
}
|
||||
dialog.show();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,17 +3,20 @@
|
|||
* Maintained by Gregor Santner, 2016-
|
||||
* https://gsantner.net/
|
||||
*
|
||||
* License: Apache 2.0 / Commercial
|
||||
* https://github.com/gsantner/opoc/#licensing
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
* License of this file: Apache 2.0 (Commercial upon request)
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
* https://github.com/gsantner/opoc/#licensing
|
||||
*
|
||||
#########################################################*/
|
||||
package net.gsantner.opoc.util;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.content.ActivityNotFoundException;
|
||||
import android.content.ComponentName;
|
||||
import android.content.Context;
|
||||
import android.content.DialogInterface;
|
||||
import android.content.Intent;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.net.Uri;
|
||||
import android.os.Build;
|
||||
import android.support.annotation.StringRes;
|
||||
|
@ -174,4 +177,12 @@ public class ActivityUtils extends net.gsantner.opoc.util.ContextUtils {
|
|||
_activity.getWindow().setStatusBarColor(color);
|
||||
}
|
||||
}
|
||||
|
||||
public void setLauncherActivityEnabled(Class activityClass, boolean enable) {
|
||||
Context context = _context.getApplicationContext();
|
||||
PackageManager pkg = context.getPackageManager();
|
||||
ComponentName component = new ComponentName(context, activityClass);
|
||||
pkg.setComponentEnabledSetting(component, enable ? PackageManager.COMPONENT_ENABLED_STATE_ENABLED : PackageManager.COMPONENT_ENABLED_STATE_DISABLED
|
||||
, PackageManager.DONT_KILL_APP);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,9 +3,9 @@
|
|||
* Maintained by Gregor Santner, 2018-
|
||||
* https://gsantner.net/
|
||||
*
|
||||
* License: Apache 2.0 / Commercial
|
||||
* https://github.com/gsantner/opoc/#licensing
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
* License of this file: Apache 2.0 (Commercial upon request)
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
* https://github.com/gsantner/opoc/#licensing
|
||||
*
|
||||
#########################################################*/
|
||||
package net.gsantner.opoc.util;
|
||||
|
|
|
@ -3,9 +3,9 @@
|
|||
* Maintained by Gregor Santner, 2016-
|
||||
* https://gsantner.net/
|
||||
*
|
||||
* License: Apache 2.0 / Commercial
|
||||
* https://github.com/gsantner/opoc/#licensing
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
* License of this file: Apache 2.0 (Commercial upon request)
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
* https://github.com/gsantner/opoc/#licensing
|
||||
*
|
||||
#########################################################*/
|
||||
package net.gsantner.opoc.util;
|
||||
|
@ -167,7 +167,7 @@ public class ContextUtils {
|
|||
public String getAppVersionName() {
|
||||
try {
|
||||
PackageManager manager = _context.getPackageManager();
|
||||
PackageInfo info = manager.getPackageInfo(getPackageName(), 0);
|
||||
PackageInfo info = manager.getPackageInfo(getPackageIdManifest(), 0);
|
||||
return info.versionName;
|
||||
} catch (PackageManager.NameNotFoundException e) {
|
||||
e.printStackTrace();
|
||||
|
@ -178,7 +178,7 @@ public class ContextUtils {
|
|||
public String getAppInstallationSource() {
|
||||
String src = null;
|
||||
try {
|
||||
src = _context.getPackageManager().getInstallerPackageName(getPackageName());
|
||||
src = _context.getPackageManager().getInstallerPackageName(getPackageIdManifest());
|
||||
} catch (Exception ignored) {
|
||||
}
|
||||
if (TextUtils.isEmpty(src)) {
|
||||
|
@ -224,13 +224,20 @@ public class ContextUtils {
|
|||
}
|
||||
|
||||
/**
|
||||
* Get this apps package name. The builtin method may fail when used with flavors
|
||||
* Get the apps base packagename, which is equal with all build flavors and variants
|
||||
*/
|
||||
public String getPackageName() {
|
||||
public String getPackageIdManifest() {
|
||||
String pkg = rstr("manifest_package_id");
|
||||
return pkg != null ? pkg : _context.getPackageName();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get this apps package name, returns the flavor specific package name.
|
||||
*/
|
||||
public String getPackageIdReal() {
|
||||
return _context.getPackageName();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get field from ${applicationId}.BuildConfig
|
||||
* May be helpful in libraries, where a access to
|
||||
|
@ -240,7 +247,7 @@ public class ContextUtils {
|
|||
* Falls back to applicationId of the app which may differ from manifest.
|
||||
*/
|
||||
public Object getBuildConfigValue(String fieldName) {
|
||||
String pkg = getPackageName() + ".BuildConfig";
|
||||
String pkg = getPackageIdManifest() + ".BuildConfig";
|
||||
try {
|
||||
Class<?> c = Class.forName(pkg);
|
||||
return c.getField(fieldName).get(null);
|
||||
|
|
|
@ -3,9 +3,9 @@
|
|||
* Maintained by Gregor Santner, 2017-
|
||||
* https://gsantner.net/
|
||||
*
|
||||
* License: Apache 2.0 / Commercial
|
||||
* https://github.com/gsantner/opoc/#licensing
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
* License of this file: Apache 2.0 (Commercial upon request)
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
* https://github.com/gsantner/opoc/#licensing
|
||||
*
|
||||
#########################################################*/
|
||||
package net.gsantner.opoc.util;
|
||||
|
@ -397,7 +397,8 @@ public class FileUtils {
|
|||
}
|
||||
|
||||
public static boolean isTextFile(File file) {
|
||||
return getMimeType(file).startsWith("text/");
|
||||
String mime = getMimeType(file);
|
||||
return mime != null && mime.startsWith("text/");
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -3,9 +3,9 @@
|
|||
* Maintained by Gregor Santner, 2017-
|
||||
* https://gsantner.net/
|
||||
*
|
||||
* License: Apache 2.0 / Commercial
|
||||
* https://github.com/gsantner/opoc/#licensing
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
* License of this file: Apache 2.0 (Commercial upon request)
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
* https://github.com/gsantner/opoc/#licensing
|
||||
*
|
||||
#########################################################*/
|
||||
package net.gsantner.opoc.util;
|
||||
|
|
|
@ -3,9 +3,9 @@
|
|||
* Maintained by Gregor Santner, 2017-
|
||||
* https://gsantner.net/
|
||||
*
|
||||
* License: Apache 2.0 / Commercial
|
||||
* https://github.com/gsantner/opoc/#licensing
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
* License of this file: Apache 2.0 (Commercial upon request)
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
* https://github.com/gsantner/opoc/#licensing
|
||||
*
|
||||
#########################################################*/
|
||||
package net.gsantner.opoc.util;
|
||||
|
|
|
@ -3,17 +3,22 @@
|
|||
* Maintained by Gregor Santner, 2017-
|
||||
* https://gsantner.net/
|
||||
*
|
||||
* License: Apache 2.0 / Commercial
|
||||
* https://github.com/gsantner/opoc/#licensing
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
* License of this file: Apache 2.0 (Commercial upon request)
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
* https://github.com/gsantner/opoc/#licensing
|
||||
*
|
||||
#########################################################*/
|
||||
package net.gsantner.opoc.util;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.content.BroadcastReceiver;
|
||||
import android.content.ClipData;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.IntentFilter;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.content.pm.ResolveInfo;
|
||||
import android.database.Cursor;
|
||||
import android.graphics.Bitmap;
|
||||
import android.graphics.Canvas;
|
||||
import android.graphics.Paint;
|
||||
|
@ -21,14 +26,18 @@ import android.net.Uri;
|
|||
import android.os.Build;
|
||||
import android.os.Environment;
|
||||
import android.os.Handler;
|
||||
import android.os.ParcelFileDescriptor;
|
||||
import android.print.PrintAttributes;
|
||||
import android.print.PrintDocumentAdapter;
|
||||
import android.print.PrintJob;
|
||||
import android.print.PrintManager;
|
||||
import android.provider.CalendarContract;
|
||||
import android.provider.MediaStore;
|
||||
import android.support.annotation.DrawableRes;
|
||||
import android.support.annotation.Nullable;
|
||||
import android.support.annotation.RequiresApi;
|
||||
import android.support.v4.content.FileProvider;
|
||||
import android.support.v4.content.LocalBroadcastManager;
|
||||
import android.support.v4.content.pm.ShortcutInfoCompat;
|
||||
import android.support.v4.content.pm.ShortcutManagerCompat;
|
||||
import android.support.v4.graphics.drawable.IconCompat;
|
||||
|
@ -38,16 +47,22 @@ import android.view.View;
|
|||
import android.webkit.WebView;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileDescriptor;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.IOException;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Random;
|
||||
|
||||
import static android.app.Activity.RESULT_OK;
|
||||
|
||||
/**
|
||||
* A utility class to ease information sharing on Android
|
||||
* Also allows to parse/fetch information out of shared information
|
||||
* A utility class to ease information sharing on Android.
|
||||
* Also allows to parse/fetch information out of shared information.
|
||||
* (M)Permissions are not checked, wrap ShareUtils methods if neccessary
|
||||
*/
|
||||
@SuppressWarnings({"UnusedReturnValue", "WeakerAccess", "SameParameterValue", "unused", "deprecation", "ConstantConditions", "ObsoleteSdkInt", "SpellCheckingInspection"})
|
||||
public class ShareUtil {
|
||||
|
@ -56,6 +71,10 @@ public class ShareUtil {
|
|||
public final static SimpleDateFormat SDF_SHORT = new SimpleDateFormat("yyMMdd-HHmm", Locale.getDefault());
|
||||
public final static String MIME_TEXT_PLAIN = "text/plain";
|
||||
|
||||
public final static int REQUEST_CAMERA_PICTURE = 50001;
|
||||
public final static int REQUEST_PICK_PICTURE = 50002;
|
||||
|
||||
protected static String _lastCameraPictureFilepath;
|
||||
|
||||
protected Context _context;
|
||||
protected String _fileProviderAuthority;
|
||||
|
@ -173,13 +192,45 @@ public class ShareUtil {
|
|||
* @param file The file to share
|
||||
* @param mimeType The files mime type
|
||||
*/
|
||||
public void shareStream(File file, String mimeType) {
|
||||
Uri fileUri = FileProvider.getUriForFile(_context, getFileProviderAuthority(), file);
|
||||
public boolean shareStream(File file, String mimeType) {
|
||||
Intent intent = new Intent(Intent.ACTION_SEND);
|
||||
intent.putExtra(Intent.EXTRA_STREAM, fileUri);
|
||||
intent.putExtra(EXTRA_FILEPATH, file.getAbsolutePath());
|
||||
intent.setType(mimeType);
|
||||
showChooser(intent, null);
|
||||
|
||||
try {
|
||||
Uri fileUri = FileProvider.getUriForFile(_context, getFileProviderAuthority(), file);
|
||||
intent.putExtra(Intent.EXTRA_STREAM, fileUri);
|
||||
showChooser(intent, null);
|
||||
return true;
|
||||
} catch (Exception e) { // FileUriExposed(API24) / IllegalArgument
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Start calendar application to add new event, with given details prefilled
|
||||
*/
|
||||
public void createCalendarAppointment(@Nullable String title, @Nullable String description, @Nullable String location, @Nullable Long... startAndEndTime) {
|
||||
Intent intent = new Intent(Intent.ACTION_INSERT).setData(CalendarContract.Events.CONTENT_URI);
|
||||
if (title != null) {
|
||||
intent.putExtra(CalendarContract.Events.TITLE, title);
|
||||
}
|
||||
if (description != null) {
|
||||
description = description.length() > 800 ? description.substring(0, 800) : description;
|
||||
intent.putExtra(CalendarContract.Events.DESCRIPTION, description);
|
||||
}
|
||||
if (location != null) {
|
||||
intent.putExtra(CalendarContract.Events.EVENT_LOCATION, location);
|
||||
}
|
||||
if (startAndEndTime != null) {
|
||||
if (startAndEndTime.length > 0 && startAndEndTime[0] > 0) {
|
||||
intent.putExtra(CalendarContract.EXTRA_EVENT_BEGIN_TIME, startAndEndTime[0]);
|
||||
}
|
||||
if (startAndEndTime.length > 1 && startAndEndTime[1] > 0) {
|
||||
intent.putExtra(CalendarContract.EXTRA_EVENT_END_TIME, startAndEndTime[1]);
|
||||
}
|
||||
}
|
||||
_context.startActivity(intent);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -187,15 +238,29 @@ public class ShareUtil {
|
|||
*
|
||||
* @param file The file to share
|
||||
*/
|
||||
public void viewFileInOtherApp(File file, @Nullable String type) {
|
||||
Uri fileUri = FileProvider.getUriForFile(_context, getFileProviderAuthority(), file);
|
||||
Intent intent = new Intent(Intent.ACTION_VIEW);
|
||||
intent.putExtra(Intent.EXTRA_STREAM, fileUri);
|
||||
intent.setData(fileUri);
|
||||
intent.putExtra(EXTRA_FILEPATH, file.getAbsolutePath());
|
||||
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
|
||||
intent.setDataAndType(fileUri, type);
|
||||
showChooser(intent, null);
|
||||
public boolean viewFileInOtherApp(File file, @Nullable String type) {
|
||||
// On some specific devices the first won't work
|
||||
Uri fileUri = null;
|
||||
try {
|
||||
fileUri = FileProvider.getUriForFile(_context, getFileProviderAuthority(), file);
|
||||
} catch (Exception ignored) {
|
||||
try {
|
||||
fileUri = Uri.fromFile(file);
|
||||
} catch (Exception ignored2) {
|
||||
}
|
||||
}
|
||||
|
||||
if (fileUri != null) {
|
||||
Intent intent = new Intent(Intent.ACTION_VIEW);
|
||||
intent.putExtra(Intent.EXTRA_STREAM, fileUri);
|
||||
intent.setData(fileUri);
|
||||
intent.putExtra(EXTRA_FILEPATH, file.getAbsolutePath());
|
||||
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
|
||||
intent.setDataAndType(fileUri, type);
|
||||
showChooser(intent, null);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -473,4 +538,228 @@ public class ShareUtil {
|
|||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Request a picture from gallery
|
||||
* Result will be available from {@link Activity#onActivityResult(int, int, Intent)}.
|
||||
* It will return the path to the image if locally stored. If retrieved from e.g. a cloud
|
||||
* service, the image will get copied to app-cache folder and it's path returned.
|
||||
*/
|
||||
public void requestGalleryPicture() {
|
||||
if (!(_context instanceof Activity)) {
|
||||
throw new RuntimeException("Error: ShareUtil.requestGalleryPicture needs an Activity Context.");
|
||||
}
|
||||
Intent intent = new Intent(Intent.ACTION_PICK, MediaStore.Images.Media.EXTERNAL_CONTENT_URI);
|
||||
((Activity) _context).startActivityForResult(intent, REQUEST_PICK_PICTURE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Request a picture from camera-like apps
|
||||
* Result ({@link String}) will be available from {@link Activity#onActivityResult(int, int, Intent)}.
|
||||
* It has set resultCode to {@link Activity#RESULT_OK} with same requestCode, if successfully
|
||||
* The requested image savepath has to be stored at caller side (not contained in intent),
|
||||
* it can be retrieved using {@link #extractResultFromActivityResult(int, int, Intent)},
|
||||
* returns null if an error happened.
|
||||
*
|
||||
* @param target Path to file to write to, if folder the filename gets app_name + millis + random filename. If null DCIM folder is used.
|
||||
*/
|
||||
public String requestCameraPicture(File target) {
|
||||
if (!(_context instanceof Activity)) {
|
||||
throw new RuntimeException("Error: ShareUtil.requestCameraPicture needs an Activity Context.");
|
||||
}
|
||||
String cameraPictureFilepath = null;
|
||||
Intent takePictureIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
|
||||
if (takePictureIntent.resolveActivity(_context.getPackageManager()) != null) {
|
||||
File photoFile;
|
||||
try {
|
||||
// Create an image file name
|
||||
if (target != null && !target.isDirectory()) {
|
||||
photoFile = target;
|
||||
} else {
|
||||
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd'T'HH-mm-ss", Locale.getDefault());
|
||||
File storageDir = target != null ? target : new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DCIM), "Camera");
|
||||
String imageFileName = ((new ContextUtils(_context).rstr("app_name")).replaceAll("[^a-zA-Z0-9\\.\\-]", "_") + "_").replace("__", "_") + sdf.format(new Date());
|
||||
photoFile = new File(storageDir, imageFileName + ".jpg");
|
||||
if (!photoFile.getParentFile().exists() && !photoFile.getParentFile().mkdirs()) {
|
||||
photoFile = File.createTempFile(imageFileName + "_", ".jpg", storageDir);
|
||||
}
|
||||
}
|
||||
|
||||
//noinspection StatementWithEmptyBody
|
||||
if (!photoFile.getParentFile().exists() && photoFile.getParentFile().mkdirs()) ;
|
||||
|
||||
// Save a file: path for use with ACTION_VIEW intents
|
||||
cameraPictureFilepath = photoFile.getAbsolutePath();
|
||||
} catch (IOException ex) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// Continue only if the File was successfully created
|
||||
if (photoFile != null) {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
|
||||
Uri uri = FileProvider.getUriForFile(_context, getFileProviderAuthority(), photoFile);
|
||||
takePictureIntent.putExtra(MediaStore.EXTRA_OUTPUT, uri);
|
||||
} else {
|
||||
takePictureIntent.putExtra(MediaStore.EXTRA_OUTPUT, Uri.fromFile(photoFile));
|
||||
}
|
||||
((Activity) _context).startActivityForResult(takePictureIntent, REQUEST_CAMERA_PICTURE);
|
||||
}
|
||||
}
|
||||
_lastCameraPictureFilepath = cameraPictureFilepath;
|
||||
return cameraPictureFilepath;
|
||||
}
|
||||
|
||||
/**
|
||||
* Extract result data from {@link Activity#onActivityResult(int, int, Intent)}.
|
||||
* Forward all arguments from activity. Only requestCodes from {@link ShareUtil} get analyzed.
|
||||
* Also may forward results via local broadcast
|
||||
*/
|
||||
public Object extractResultFromActivityResult(int requestCode, int resultCode, Intent data) {
|
||||
switch (requestCode) {
|
||||
case REQUEST_CAMERA_PICTURE: {
|
||||
String picturePath = (resultCode == RESULT_OK) ? _lastCameraPictureFilepath : null;
|
||||
if (picturePath != null) {
|
||||
sendLocalBroadcastWithStringExtra(REQUEST_CAMERA_PICTURE + "", EXTRA_FILEPATH, picturePath);
|
||||
}
|
||||
return picturePath;
|
||||
}
|
||||
case REQUEST_PICK_PICTURE: {
|
||||
if (resultCode == RESULT_OK && data != null) {
|
||||
Uri selectedImage = data.getData();
|
||||
String[] filePathColumn = {MediaStore.Images.Media.DATA};
|
||||
String picturePath = null;
|
||||
|
||||
Cursor cursor = _context.getContentResolver().query(selectedImage, filePathColumn, null, null, null);
|
||||
if (cursor != null && cursor.moveToFirst()) {
|
||||
for (String column : filePathColumn) {
|
||||
int curColIndex = cursor.getColumnIndex(column);
|
||||
if (curColIndex == -1) {
|
||||
continue;
|
||||
}
|
||||
picturePath = cursor.getString(curColIndex);
|
||||
if (!TextUtils.isEmpty(picturePath)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
cursor.close();
|
||||
}
|
||||
|
||||
// Retrieve image from file descriptor / Cloud, e.g.: Google Drive, Picasa
|
||||
if (picturePath == null && Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
|
||||
try {
|
||||
ParcelFileDescriptor parcelFileDescriptor = _context.getContentResolver().openFileDescriptor(selectedImage, "r");
|
||||
if (parcelFileDescriptor != null) {
|
||||
FileDescriptor fileDescriptor = parcelFileDescriptor.getFileDescriptor();
|
||||
FileInputStream input = new FileInputStream(fileDescriptor);
|
||||
|
||||
// Create temporary file in cache directory
|
||||
picturePath = File.createTempFile("image", "tmp", _context.getCacheDir()).getAbsolutePath();
|
||||
FileUtils.writeFile(new File(picturePath), FileUtils.readCloseBinaryStream(input));
|
||||
}
|
||||
} catch (IOException ignored) {
|
||||
// nothing we can do here, null value will be handled below
|
||||
}
|
||||
}
|
||||
|
||||
// Return path to picture on success, else null
|
||||
if (picturePath != null) {
|
||||
sendLocalBroadcastWithStringExtra(REQUEST_CAMERA_PICTURE + "", EXTRA_FILEPATH, picturePath);
|
||||
}
|
||||
return picturePath;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Send a local broadcast (to receive within app), with given action and string-extra+value.
|
||||
* This is a convenience method for quickly sending just one thing.
|
||||
*/
|
||||
public void sendLocalBroadcastWithStringExtra(String action, String extra, CharSequence value) {
|
||||
Intent intent = new Intent(action);
|
||||
intent.putExtra(extra, value);
|
||||
LocalBroadcastManager.getInstance(_context).sendBroadcast(intent);
|
||||
}
|
||||
|
||||
/**
|
||||
* Receive broadcast results via a callback method
|
||||
*
|
||||
* @param callback Function to call with received {@link Intent}
|
||||
* @param autoUnregister wether or not to automatically unregister receiver after first match
|
||||
* @param filterActions All {@link IntentFilter} actions to filter for
|
||||
* @return The created instance. Has to be unregistered on {@link Activity} lifecycle events.
|
||||
*/
|
||||
public BroadcastReceiver receiveResultFromLocalBroadcast(Callback.a2<Intent, BroadcastReceiver> callback, boolean autoUnregister, String... filterActions) {
|
||||
IntentFilter intentFilter = new IntentFilter();
|
||||
for (String filterAction : filterActions) {
|
||||
intentFilter.addAction(filterAction);
|
||||
}
|
||||
final BroadcastReceiver br = new BroadcastReceiver() {
|
||||
@Override
|
||||
public void onReceive(Context context, Intent intent) {
|
||||
if (intent != null) {
|
||||
if (autoUnregister) {
|
||||
LocalBroadcastManager.getInstance(_context).unregisterReceiver(this);
|
||||
}
|
||||
try {
|
||||
callback.callback(intent, this);
|
||||
} catch (Exception ignored) {
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
LocalBroadcastManager.getInstance(_context).registerReceiver(br, intentFilter);
|
||||
return br;
|
||||
}
|
||||
|
||||
/**
|
||||
* Request edit of image (by image editor/viewer - for example to crop image)
|
||||
*
|
||||
* @param file File that should be edited
|
||||
*/
|
||||
public void requestPictureEdit(File file) {
|
||||
Uri uri = getUriByFileProviderAuthority(file);
|
||||
int flags = Intent.FLAG_GRANT_WRITE_URI_PERMISSION | Intent.FLAG_GRANT_READ_URI_PERMISSION;
|
||||
|
||||
Intent intent = new Intent(Intent.ACTION_EDIT);
|
||||
intent.setDataAndType(uri, "image/*");
|
||||
intent.addFlags(flags);
|
||||
intent.putExtra(MediaStore.EXTRA_OUTPUT, uri);
|
||||
intent.putExtra(EXTRA_FILEPATH, file.getAbsolutePath());
|
||||
|
||||
for (ResolveInfo resolveInfo : _context.getPackageManager().queryIntentActivities(intent, PackageManager.MATCH_DEFAULT_ONLY)) {
|
||||
String packageName = resolveInfo.activityInfo.packageName;
|
||||
_context.grantUriPermission(packageName, uri, flags);
|
||||
}
|
||||
_context.startActivity(Intent.createChooser(intent, null));
|
||||
}
|
||||
|
||||
/**
|
||||
* Get content://media/ Uri for given file, or null if not indexed
|
||||
*
|
||||
* @param file Target file
|
||||
* @param mode 1 for picture, 2 for video, anything else for other
|
||||
* @return
|
||||
*/
|
||||
public Uri getMediaUri(File file, int mode) {
|
||||
Uri uri = MediaStore.Files.getContentUri("external");
|
||||
uri = (mode != 0) ? (mode == 1 ? MediaStore.Images.Media.EXTERNAL_CONTENT_URI : MediaStore.Video.Media.EXTERNAL_CONTENT_URI) : uri;
|
||||
|
||||
Cursor cursor = null;
|
||||
try {
|
||||
cursor = _context.getContentResolver().query(uri, new String[]{MediaStore.Images.Media._ID}, MediaStore.Images.Media.DATA + "= ?", new String[]{file.getAbsolutePath()}, null);
|
||||
if (cursor != null && cursor.moveToFirst()) {
|
||||
int mediaid = cursor.getInt(cursor.getColumnIndex(MediaStore.Images.Media._ID));
|
||||
return Uri.withAppendedPath(uri, mediaid + "");
|
||||
}
|
||||
} catch (Exception ignored) {
|
||||
} finally {
|
||||
if (cursor != null) {
|
||||
cursor.close();
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
|
15
build.gradle
15
build.gradle
|
@ -1,12 +1,11 @@
|
|||
/*#######################################################
|
||||
*
|
||||
* Maintained by Gregor Santner, 2017-
|
||||
* https://gsantner.net/
|
||||
*
|
||||
* License: Apache 2.0 / Commercial
|
||||
* https://github.com/gsantner/opoc/#licensing
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
*
|
||||
* Maintained by Gregor Santner, 2017-
|
||||
* https://gsantner.net/
|
||||
*
|
||||
* License of this file: Apache 2.0 (Commercial upon request)
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
#########################################################*/
|
||||
import java.text.SimpleDateFormat
|
||||
|
||||
|
|
Loading…
Reference in a new issue