Compare commits
51 Commits
94c947305b
...
fee1b1516f
Author | SHA1 | Date |
---|---|---|
Daniel Micay | fee1b1516f | |
dependabot[bot] | bc77ecbcc6 | |
Daniel Micay | 955bed3614 | |
Daniel Micay | ee3605428e | |
Daniel Micay | e967af2397 | |
Daniel Micay | 9ea5cb1802 | |
Daniel Micay | a307f2892c | |
Pratyush | 8c795d4552 | |
Daniel Micay | d7ca71770f | |
Daniel Micay | a29ec202a7 | |
Pratyush | ea9a57fabe | |
Pratyush | 68fc48d3a9 | |
quh4gko8 | 3ebdfd0a11 | |
quh4gko8 | ff11df007f | |
Daniel Micay | fa2db54804 | |
Patryk Mis | 7634c00f59 | |
Daniel Micay | f67021e975 | |
dependabot[bot] | adb87cbaef | |
Daniel Micay | 09ccfb069d | |
Daniel Micay | 2a91d95eef | |
dependabot[bot] | a48213c450 | |
dependabot[bot] | 2f4c1ebfed | |
Daniel Micay | 22b400c68f | |
Daniel Micay | 6a6a263b0b | |
Daniel Micay | 8cd685c8c7 | |
Daniel Micay | be3f43e7a4 | |
Daniel Micay | 5eb98841d6 | |
Daniel Micay | e297fdf7e4 | |
Daniel Micay | 9355f54956 | |
dependabot[bot] | 5dfdaa2c17 | |
June | 3411fb0426 | |
dependabot[bot] | af567a5c0c | |
Daniel Micay | 6a7982ce80 | |
Daniel Micay | 1a3e816cfc | |
Daniel Micay | c6113df31d | |
Daniel Micay | db98371c9d | |
Pratyush | 87c71ddac2 | |
Daniel Micay | 7dab1cdc91 | |
Daniel Micay | 61d204d188 | |
Daniel Micay | 96651d02af | |
Daniel Micay | 21d7b9d76e | |
Pratyush | eb6eb8046c | |
dependabot[bot] | c1a1263bd5 | |
smdyv | d71f804b5a | |
Pratyush | ba9a6c8206 | |
Daniel Micay | c0eea02bb1 | |
Patryk Mis | eb6c14740f | |
dependabot[bot] | 6847883605 | |
dependabot[bot] | 975dfb966c | |
dependabot[bot] | ec965ddaaa | |
June | 087a01cf72 |
|
@ -10,11 +10,11 @@ jobs:
|
|||
- uses: actions/checkout@v3
|
||||
with:
|
||||
submodules: true
|
||||
- name: Set up JDK 17
|
||||
uses: actions/setup-java@v2
|
||||
- name: Set up JDK 18
|
||||
uses: actions/setup-java@v3
|
||||
with:
|
||||
distribution: 'temurin'
|
||||
java-version: 17
|
||||
java-version: 18
|
||||
cache: gradle
|
||||
- name: Build with Gradle
|
||||
run: ./gradlew build --no-daemon
|
||||
|
|
|
@ -32,14 +32,16 @@ android {
|
|||
}
|
||||
}
|
||||
|
||||
compileSdk = 32
|
||||
buildToolsVersion = "32.0.0"
|
||||
compileSdk = 33
|
||||
buildToolsVersion = "33.0.0"
|
||||
|
||||
namespace = "app.grapheneos.pdfviewer"
|
||||
|
||||
defaultConfig {
|
||||
applicationId = "app.grapheneos.pdfviewer"
|
||||
minSdk = 26
|
||||
targetSdk = 32
|
||||
versionCode = 13
|
||||
targetSdk = 33
|
||||
versionCode = 15
|
||||
versionName = versionCode.toString()
|
||||
resourceConfigurations.add("en")
|
||||
}
|
||||
|
@ -82,6 +84,6 @@ android {
|
|||
}
|
||||
|
||||
dependencies {
|
||||
implementation("androidx.appcompat:appcompat:1.4.1")
|
||||
implementation("com.google.android.material:material:1.5.0")
|
||||
implementation("androidx.appcompat:appcompat:1.5.1")
|
||||
implementation("com.google.android.material:material:1.6.1")
|
||||
}
|
||||
|
|
|
@ -1,7 +1,8 @@
|
|||
<lint>
|
||||
<!-- full backups are desired -->
|
||||
<issue id="AllowBackup">
|
||||
<ignore path="src/main/AndroidManifest.xml"/>
|
||||
<!-- overly aggressive check -->
|
||||
<issue id="VectorPath">
|
||||
<ignore path="src/main/res/drawable/ic_rotate_left_24dp.xml"/>
|
||||
<ignore path="src/main/res/drawable/ic_rotate_right_24dp.xml"/>
|
||||
</issue>
|
||||
|
||||
<!-- Google app indexing doesn't make any sense for this app -->
|
||||
|
|
|
@ -1,11 +1,10 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
package="app.grapheneos.pdfviewer"
|
||||
android:targetSandboxVersion="2">
|
||||
<original-package android:name="org.grapheneos.pdfviewer" />
|
||||
|
||||
<application android:icon="@mipmap/ic_launcher"
|
||||
android:roundIcon="@mipmap/ic_launcher_round"
|
||||
android:roundIcon="@mipmap/ic_launcher"
|
||||
android:label="@string/app_name"
|
||||
android:theme="@style/AppTheme"
|
||||
android:allowBackup="true">
|
||||
|
|
|
@ -198,15 +198,28 @@ function isTextSelected() {
|
|||
return window.getSelection().toString() !== "";
|
||||
}
|
||||
|
||||
pdfjsLib.getDocument("https://localhost/placeholder.pdf").promise.then(function(newDoc) {
|
||||
function loadDocument() {
|
||||
const pdfPassword = channel.getPassword();
|
||||
const loadingTask = pdfjsLib.getDocument({ url: "https://localhost/placeholder.pdf", password: pdfPassword });
|
||||
loadingTask.onPassword = (_, error) => {
|
||||
if (error === pdfjsLib.PasswordResponses.NEED_PASSWORD) {
|
||||
channel.showPasswordPrompt();
|
||||
} else if (error === pdfjsLib.PasswordResponses.INCORRECT_PASSWORD) {
|
||||
channel.invalidPassword();
|
||||
}
|
||||
}
|
||||
|
||||
loadingTask.promise.then(function (newDoc) {
|
||||
channel.onLoaded();
|
||||
pdfDoc = newDoc;
|
||||
channel.setNumPages(pdfDoc.numPages);
|
||||
pdfDoc.getMetadata().then(function(data) {
|
||||
pdfDoc.getMetadata().then(function (data) {
|
||||
channel.setDocumentProperties(JSON.stringify(data.info));
|
||||
}).catch(function(error) {
|
||||
}).catch(function (error) {
|
||||
console.log("getMetadata error: " + error);
|
||||
});
|
||||
renderPage(channel.getPage(), false, false);
|
||||
}).catch(function(error) {
|
||||
console.log("getDocument error: " + error);
|
||||
});
|
||||
}, function (reason) {
|
||||
console.error(reason.name + ": " + reason.message);
|
||||
});
|
||||
}
|
||||
|
|
Binary file not shown.
Before Width: | Height: | Size: 15 KiB After Width: | Height: | Size: 6.7 KiB |
|
@ -0,0 +1,25 @@
|
|||
package app.grapheneos.pdfviewer
|
||||
|
||||
import android.content.Context
|
||||
import android.net.Uri
|
||||
import java.io.FileNotFoundException
|
||||
import java.io.IOException
|
||||
import java.io.InputStream
|
||||
import java.io.OutputStream
|
||||
|
||||
@Throws(FileNotFoundException::class, IOException::class)
|
||||
fun saveAs(context: Context, existingUri: Uri, saveAs: Uri) {
|
||||
|
||||
context.asInputStream(existingUri)?.use { inputStream ->
|
||||
context.asOutputStream(saveAs)?.use { outputStream ->
|
||||
outputStream.write(inputStream.readBytes())
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Throws(FileNotFoundException::class)
|
||||
private fun Context.asInputStream(uri: Uri): InputStream? = contentResolver.openInputStream(uri)
|
||||
|
||||
@Throws(FileNotFoundException::class)
|
||||
private fun Context.asOutputStream(uri: Uri): OutputStream? = contentResolver.openOutputStream(uri)
|
|
@ -1,12 +1,12 @@
|
|||
package app.grapheneos.pdfviewer;
|
||||
|
||||
import android.annotation.SuppressLint;
|
||||
import android.app.Activity;
|
||||
import android.content.Intent;
|
||||
import android.content.pm.PackageInfo;
|
||||
import android.content.res.ColorStateList;
|
||||
import android.graphics.Color;
|
||||
import android.net.Uri;
|
||||
import android.os.Build;
|
||||
import android.os.Bundle;
|
||||
import android.util.Log;
|
||||
import android.view.Gravity;
|
||||
|
@ -25,12 +25,16 @@ import android.webkit.WebViewClient;
|
|||
import android.widget.TextView;
|
||||
import android.widget.Toast;
|
||||
|
||||
import androidx.activity.result.ActivityResultLauncher;
|
||||
import androidx.activity.result.contract.ActivityResultContracts;
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.appcompat.app.AppCompatActivity;
|
||||
import androidx.core.graphics.Insets;
|
||||
import androidx.core.view.ViewCompat;
|
||||
import androidx.core.view.WindowCompat;
|
||||
import androidx.core.view.WindowInsetsCompat;
|
||||
import androidx.fragment.app.Fragment;
|
||||
import androidx.lifecycle.ViewModelProvider;
|
||||
import androidx.loader.app.LoaderManager;
|
||||
import androidx.loader.content.Loader;
|
||||
|
||||
|
@ -38,11 +42,14 @@ import com.google.android.material.snackbar.Snackbar;
|
|||
|
||||
import app.grapheneos.pdfviewer.databinding.PdfviewerBinding;
|
||||
import app.grapheneos.pdfviewer.fragment.DocumentPropertiesFragment;
|
||||
import app.grapheneos.pdfviewer.fragment.PasswordPromptFragment;
|
||||
import app.grapheneos.pdfviewer.fragment.JumpToPageFragment;
|
||||
import app.grapheneos.pdfviewer.loader.DocumentPropertiesLoader;
|
||||
import app.grapheneos.pdfviewer.viewModel.PasswordStatus;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
|
||||
|
@ -53,6 +60,7 @@ public class PdfViewer extends AppCompatActivity implements LoaderManager.Loader
|
|||
private static final String STATE_PAGE = "page";
|
||||
private static final String STATE_ZOOM_RATIO = "zoomRatio";
|
||||
private static final String STATE_DOCUMENT_ORIENTATION_DEGREES = "documentOrientationDegrees";
|
||||
private static final String STATE_ENCRYPTED_DOCUMENT_PASSWORD = "encrypted_document_password";
|
||||
private static final String KEY_PROPERTIES = "properties";
|
||||
private static final int MIN_WEBVIEW_RELEASE = 89;
|
||||
|
||||
|
@ -78,6 +86,7 @@ public class PdfViewer extends AppCompatActivity implements LoaderManager.Loader
|
|||
"document-domain=(), " +
|
||||
"encrypted-media=(), " +
|
||||
"fullscreen=(), " +
|
||||
"gamepad=(), " +
|
||||
"geolocation=(), " +
|
||||
"gyroscope=(), " +
|
||||
"hid=(), " +
|
||||
|
@ -91,6 +100,7 @@ public class PdfViewer extends AppCompatActivity implements LoaderManager.Loader
|
|||
"publickey-credentials-get=(), " +
|
||||
"screen-wake-lock=(), " +
|
||||
"serial=(), " +
|
||||
"speaker-selection=(), " +
|
||||
"sync-xhr=(), " +
|
||||
"usb=(), " +
|
||||
"xr-spatial-tracking=()";
|
||||
|
@ -99,7 +109,6 @@ public class PdfViewer extends AppCompatActivity implements LoaderManager.Loader
|
|||
private static final float MAX_ZOOM_RATIO = 1.5f;
|
||||
private static final int ALPHA_LOW = 130;
|
||||
private static final int ALPHA_HIGH = 255;
|
||||
private static final int ACTION_OPEN_DOCUMENT_REQUEST_CODE = 1;
|
||||
private static final int STATE_LOADED = 1;
|
||||
private static final int STATE_END = 2;
|
||||
private static final int PADDING = 10;
|
||||
|
@ -110,6 +119,7 @@ public class PdfViewer extends AppCompatActivity implements LoaderManager.Loader
|
|||
private float mZoomRatio = 1f;
|
||||
private int mDocumentOrientationDegrees;
|
||||
private int mDocumentState;
|
||||
private String mEncryptedDocumentPassword;
|
||||
private List<CharSequence> mDocumentProperties;
|
||||
private InputStream mInputStream;
|
||||
|
||||
|
@ -117,6 +127,36 @@ public class PdfViewer extends AppCompatActivity implements LoaderManager.Loader
|
|||
private TextView mTextView;
|
||||
private Toast mToast;
|
||||
private Snackbar snackbar;
|
||||
private PasswordPromptFragment mPasswordPromptFragment;
|
||||
public PasswordStatus passwordValidationViewModel;
|
||||
|
||||
private final ActivityResultLauncher<Intent> openDocumentLauncher = registerForActivityResult(
|
||||
new ActivityResultContracts.StartActivityForResult(), result -> {
|
||||
if (result == null) return;
|
||||
if (result.getResultCode() != RESULT_OK) return;
|
||||
Intent resultData = result.getData();
|
||||
if (resultData != null) {
|
||||
mUri = result.getData().getData();
|
||||
mPage = 1;
|
||||
mDocumentProperties = null;
|
||||
mEncryptedDocumentPassword = "";
|
||||
loadPdf();
|
||||
invalidateOptionsMenu();
|
||||
}
|
||||
});
|
||||
|
||||
private final ActivityResultLauncher<Intent> saveAsLauncher = registerForActivityResult(
|
||||
new ActivityResultContracts.StartActivityForResult(), result -> {
|
||||
if (result == null) return;
|
||||
if (result.getResultCode() != RESULT_OK) return;
|
||||
Intent resultData = result.getData();
|
||||
if (resultData != null) {
|
||||
Uri path = resultData.getData();
|
||||
if (path != null) {
|
||||
saveDocumentAs(path);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
private class Channel {
|
||||
@JavascriptInterface
|
||||
|
@ -150,6 +190,32 @@ public class PdfViewer extends AppCompatActivity implements LoaderManager.Loader
|
|||
args.putString(KEY_PROPERTIES, properties);
|
||||
runOnUiThread(() -> LoaderManager.getInstance(PdfViewer.this).restartLoader(DocumentPropertiesLoader.ID, args, PdfViewer.this));
|
||||
}
|
||||
|
||||
@JavascriptInterface
|
||||
public void showPasswordPrompt() {
|
||||
if (!getPasswordPromptFragment().isAdded()){
|
||||
getPasswordPromptFragment().show(getSupportFragmentManager(), PasswordPromptFragment.class.getName());
|
||||
}
|
||||
passwordValidationViewModel.passwordMissing();
|
||||
}
|
||||
|
||||
@JavascriptInterface
|
||||
public void invalidPassword() {
|
||||
runOnUiThread(() -> passwordValidationViewModel.invalid());
|
||||
}
|
||||
|
||||
@JavascriptInterface
|
||||
public void onLoaded() {
|
||||
passwordValidationViewModel.validated();
|
||||
if (getPasswordPromptFragment().isAdded()) {
|
||||
getPasswordPromptFragment().dismiss();
|
||||
}
|
||||
}
|
||||
|
||||
@JavascriptInterface
|
||||
public String getPassword() {
|
||||
return mEncryptedDocumentPassword != null ? mEncryptedDocumentPassword : "";
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -159,6 +225,7 @@ public class PdfViewer extends AppCompatActivity implements LoaderManager.Loader
|
|||
binding = PdfviewerBinding.inflate(getLayoutInflater());
|
||||
setContentView(binding.getRoot());
|
||||
setSupportActionBar(binding.toolbar);
|
||||
passwordValidationViewModel = new ViewModelProvider(this, ViewModelProvider.AndroidViewModelFactory.getInstance(getApplication())).get(PasswordStatus.class);
|
||||
|
||||
WindowCompat.setDecorFitsSystemWindows(getWindow(), false);
|
||||
|
||||
|
@ -214,6 +281,12 @@ public class PdfViewer extends AppCompatActivity implements LoaderManager.Loader
|
|||
Log.d(TAG, "path " + path);
|
||||
|
||||
if ("/placeholder.pdf".equals(path)) {
|
||||
maybeCloseInputStream();
|
||||
try {
|
||||
mInputStream = getContentResolver().openInputStream(mUri);
|
||||
} catch (FileNotFoundException ignored) {
|
||||
snackbar.setText(R.string.error_while_opening).show();
|
||||
}
|
||||
return new WebResourceResponse("application/pdf", null, mInputStream);
|
||||
}
|
||||
|
||||
|
@ -247,6 +320,7 @@ public class PdfViewer extends AppCompatActivity implements LoaderManager.Loader
|
|||
public void onPageFinished(WebView view, String url) {
|
||||
mDocumentState = STATE_LOADED;
|
||||
invalidateOptionsMenu();
|
||||
loadPdfWithPassword(mEncryptedDocumentPassword);
|
||||
}
|
||||
});
|
||||
|
||||
|
@ -297,7 +371,7 @@ public class PdfViewer extends AppCompatActivity implements LoaderManager.Loader
|
|||
// loader manager impl so that the result will be delivered.
|
||||
LoaderManager.getInstance(this);
|
||||
|
||||
snackbar = Snackbar.make(binding.webview, "", Snackbar.LENGTH_LONG);
|
||||
snackbar = Snackbar.make(binding.getRoot(), "", Snackbar.LENGTH_LONG);
|
||||
|
||||
final Intent intent = getIntent();
|
||||
if (Intent.ACTION_VIEW.equals(intent.getAction())) {
|
||||
|
@ -310,10 +384,15 @@ public class PdfViewer extends AppCompatActivity implements LoaderManager.Loader
|
|||
}
|
||||
|
||||
if (savedInstanceState != null) {
|
||||
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.TIRAMISU) {
|
||||
mUri = savedInstanceState.getParcelable(STATE_URI);
|
||||
} else {
|
||||
mUri = savedInstanceState.getParcelable(STATE_URI, Uri.class);
|
||||
}
|
||||
mPage = savedInstanceState.getInt(STATE_PAGE);
|
||||
mZoomRatio = savedInstanceState.getFloat(STATE_ZOOM_RATIO);
|
||||
mDocumentOrientationDegrees = savedInstanceState.getInt(STATE_DOCUMENT_ORIENTATION_DEGREES);
|
||||
mEncryptedDocumentPassword = savedInstanceState.getString(STATE_ENCRYPTED_DOCUMENT_PASSWORD);
|
||||
}
|
||||
|
||||
if (mUri != null) {
|
||||
|
@ -326,6 +405,38 @@ public class PdfViewer extends AppCompatActivity implements LoaderManager.Loader
|
|||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onDestroy() {
|
||||
super.onDestroy();
|
||||
binding.webview.removeJavascriptInterface("channel");
|
||||
binding.getRoot().removeView(binding.webview);
|
||||
binding.webview.destroy();
|
||||
maybeCloseInputStream();
|
||||
}
|
||||
|
||||
void maybeCloseInputStream() {
|
||||
InputStream stream = mInputStream;
|
||||
if (stream == null) {
|
||||
return;
|
||||
}
|
||||
mInputStream = null;
|
||||
try {
|
||||
stream.close();
|
||||
} catch (IOException ignored) {}
|
||||
}
|
||||
|
||||
private PasswordPromptFragment getPasswordPromptFragment() {
|
||||
if (mPasswordPromptFragment == null) {
|
||||
final Fragment fragment = getSupportFragmentManager().findFragmentByTag(PasswordPromptFragment.class.getName());
|
||||
if (fragment != null) {
|
||||
mPasswordPromptFragment = (PasswordPromptFragment) fragment;
|
||||
} else {
|
||||
mPasswordPromptFragment = new PasswordPromptFragment();
|
||||
}
|
||||
}
|
||||
return mPasswordPromptFragment;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onResume() {
|
||||
super.onResume();
|
||||
|
@ -372,14 +483,21 @@ public class PdfViewer extends AppCompatActivity implements LoaderManager.Loader
|
|||
}
|
||||
mInputStream = getContentResolver().openInputStream(mUri);
|
||||
} catch (IOException e) {
|
||||
snackbar.setText(R.string.io_error).show();
|
||||
snackbar.setText(R.string.error_while_opening).show();
|
||||
return;
|
||||
}
|
||||
|
||||
mDocumentState = 0;
|
||||
showSystemUi();
|
||||
invalidateOptionsMenu();
|
||||
binding.webview.loadUrl("https://localhost/viewer.html");
|
||||
}
|
||||
|
||||
public void loadPdfWithPassword(final String password) {
|
||||
mEncryptedDocumentPassword = password;
|
||||
binding.webview.evaluateJavascript("loadDocument()", null);
|
||||
}
|
||||
|
||||
private void renderPage(final int zoom) {
|
||||
binding.webview.evaluateJavascript("onRenderPage(" + zoom + ")", null);
|
||||
}
|
||||
|
@ -396,7 +514,7 @@ public class PdfViewer extends AppCompatActivity implements LoaderManager.Loader
|
|||
Intent intent = new Intent(Intent.ACTION_OPEN_DOCUMENT);
|
||||
intent.addCategory(Intent.CATEGORY_OPENABLE);
|
||||
intent.setType("application/pdf");
|
||||
startActivityForResult(intent, ACTION_OPEN_DOCUMENT_REQUEST_CODE);
|
||||
openDocumentLauncher.launch(intent);
|
||||
}
|
||||
|
||||
private void shareDocument() {
|
||||
|
@ -476,21 +594,7 @@ public class PdfViewer extends AppCompatActivity implements LoaderManager.Loader
|
|||
savedInstanceState.putInt(STATE_PAGE, mPage);
|
||||
savedInstanceState.putFloat(STATE_ZOOM_RATIO, mZoomRatio);
|
||||
savedInstanceState.putInt(STATE_DOCUMENT_ORIENTATION_DEGREES, mDocumentOrientationDegrees);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onActivityResult(int requestCode, int resultCode, Intent resultData) {
|
||||
super.onActivityResult(requestCode, resultCode, resultData);
|
||||
|
||||
if (requestCode == ACTION_OPEN_DOCUMENT_REQUEST_CODE && resultCode == Activity.RESULT_OK) {
|
||||
if (resultData != null) {
|
||||
mUri = resultData.getData();
|
||||
mPage = 1;
|
||||
mDocumentProperties = null;
|
||||
loadPdf();
|
||||
invalidateOptionsMenu();
|
||||
}
|
||||
}
|
||||
savedInstanceState.putString(STATE_ENCRYPTED_DOCUMENT_PASSWORD, mEncryptedDocumentPassword);
|
||||
}
|
||||
|
||||
private void showPageNumber() {
|
||||
|
@ -515,10 +619,10 @@ public class PdfViewer extends AppCompatActivity implements LoaderManager.Loader
|
|||
|
||||
@Override
|
||||
public boolean onPrepareOptionsMenu(Menu menu) {
|
||||
final int[] ids = { R.id.action_zoom_in, R.id.action_zoom_out, R.id.action_jump_to_page,
|
||||
R.id.action_next, R.id.action_previous, R.id.action_first, R.id.action_last,
|
||||
R.id.action_rotate_clockwise, R.id.action_rotate_counterclockwise,
|
||||
R.id.action_view_document_properties, R.id.action_share };
|
||||
final int[] ids = {R.id.action_jump_to_page, R.id.action_next, R.id.action_previous,
|
||||
R.id.action_first, R.id.action_last, R.id.action_rotate_clockwise,
|
||||
R.id.action_rotate_counterclockwise, R.id.action_view_document_properties,
|
||||
R.id.action_share, R.id.action_save_as};
|
||||
if (mDocumentState < STATE_LOADED) {
|
||||
for (final int id : ids) {
|
||||
final MenuItem item = menu.findItem(id);
|
||||
|
@ -537,11 +641,10 @@ public class PdfViewer extends AppCompatActivity implements LoaderManager.Loader
|
|||
}
|
||||
|
||||
enableDisableMenuItem(menu.findItem(R.id.action_open), getWebViewRelease() >= MIN_WEBVIEW_RELEASE);
|
||||
enableDisableMenuItem(menu.findItem(R.id.action_zoom_in), mZoomRatio != MAX_ZOOM_RATIO);
|
||||
enableDisableMenuItem(menu.findItem(R.id.action_zoom_out), mZoomRatio != MIN_ZOOM_RATIO);
|
||||
enableDisableMenuItem(menu.findItem(R.id.action_share), mUri != null);
|
||||
enableDisableMenuItem(menu.findItem(R.id.action_next), mPage < mNumPages);
|
||||
enableDisableMenuItem(menu.findItem(R.id.action_previous), mPage > 1);
|
||||
enableDisableMenuItem(menu.findItem(R.id.action_save_as), mUri != null);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
@ -564,12 +667,6 @@ public class PdfViewer extends AppCompatActivity implements LoaderManager.Loader
|
|||
} else if (itemId == R.id.action_open) {
|
||||
openDocument();
|
||||
return true;
|
||||
} else if (itemId == R.id.action_zoom_out) {
|
||||
zoomOut(0.25f, true);
|
||||
return true;
|
||||
} else if (itemId == R.id.action_zoom_in) {
|
||||
zoomIn(0.25f, true);
|
||||
return true;
|
||||
} else if (itemId == R.id.action_rotate_clockwise) {
|
||||
documentOrientationChanged(90);
|
||||
return true;
|
||||
|
@ -588,8 +685,42 @@ public class PdfViewer extends AppCompatActivity implements LoaderManager.Loader
|
|||
} else if (itemId == R.id.action_share) {
|
||||
shareDocument();
|
||||
return true;
|
||||
} else if (itemId == R.id.action_save_as) {
|
||||
saveDocument();
|
||||
}
|
||||
|
||||
return super.onOptionsItemSelected(item);
|
||||
}
|
||||
|
||||
private void saveDocument() {
|
||||
Intent intent = new Intent(Intent.ACTION_CREATE_DOCUMENT);
|
||||
intent.addCategory(Intent.CATEGORY_OPENABLE);
|
||||
intent.setType("application/pdf");
|
||||
intent.putExtra(Intent.EXTRA_TITLE, getCurrentDocumentName());
|
||||
saveAsLauncher.launch(intent);
|
||||
}
|
||||
|
||||
private String getCurrentDocumentName() {
|
||||
if (mDocumentProperties == null || mDocumentProperties.isEmpty()) return "";
|
||||
String fileName = "";
|
||||
String title = "";
|
||||
for (CharSequence property : mDocumentProperties) {
|
||||
if (property.toString().startsWith("File name:")) {
|
||||
fileName = property.toString().replace("File name:", "");
|
||||
}
|
||||
if (property.toString().startsWith("Title:-")) {
|
||||
title = property.toString().replace("Title:-", "");
|
||||
}
|
||||
}
|
||||
return fileName.length() > 2 ? fileName : title;
|
||||
}
|
||||
|
||||
private void saveDocumentAs(Uri uri) {
|
||||
try {
|
||||
KtUtilsKt.saveAs(this, mUri, uri);
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
snackbar.setText(R.string.error_while_saving).show();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -39,14 +39,13 @@ public class Utils {
|
|||
|
||||
final Calendar calendar = Calendar.getInstance();
|
||||
final int currentYear = calendar.get(Calendar.YEAR);
|
||||
int year;
|
||||
|
||||
// Year is required
|
||||
String field = date.substring(position += 2, 6);
|
||||
if (!TextUtils.isDigitsOnly(field)) {
|
||||
throw new ParseException("Invalid year", position);
|
||||
}
|
||||
year = Integer.parseInt(field);
|
||||
int year = Integer.parseInt(field);
|
||||
if (year > currentYear) {
|
||||
year = currentYear;
|
||||
}
|
||||
|
|
|
@ -0,0 +1,102 @@
|
|||
package app.grapheneos.pdfviewer.fragment
|
||||
|
||||
import android.app.Dialog
|
||||
import android.content.DialogInterface
|
||||
import android.os.Bundle
|
||||
import android.text.Editable
|
||||
import android.text.TextUtils
|
||||
import android.text.TextWatcher
|
||||
import android.view.LayoutInflater
|
||||
import android.view.WindowManager
|
||||
import android.view.inputmethod.EditorInfo.IME_ACTION_DONE
|
||||
import androidx.appcompat.app.AlertDialog
|
||||
import androidx.fragment.app.DialogFragment
|
||||
import app.grapheneos.pdfviewer.PdfViewer
|
||||
import app.grapheneos.pdfviewer.R
|
||||
import app.grapheneos.pdfviewer.databinding.PasswordDialogFragmentBinding
|
||||
import app.grapheneos.pdfviewer.viewModel.PasswordStatus
|
||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
||||
import com.google.android.material.textfield.TextInputEditText
|
||||
import com.google.android.material.textfield.TextInputLayout
|
||||
|
||||
class PasswordPromptFragment : DialogFragment() {
|
||||
|
||||
private lateinit var passwordLayout : TextInputLayout
|
||||
private lateinit var passwordEditText : TextInputEditText
|
||||
|
||||
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
|
||||
val passwordPrompt = MaterialAlertDialogBuilder(requireContext())
|
||||
val passwordDialogFragmentBinding =
|
||||
PasswordDialogFragmentBinding.inflate(LayoutInflater.from(requireContext()))
|
||||
passwordLayout = passwordDialogFragmentBinding.pdfPasswordTextInputLayout
|
||||
passwordEditText = passwordDialogFragmentBinding.pdfPasswordEditText
|
||||
passwordPrompt.setView(passwordDialogFragmentBinding.root)
|
||||
passwordEditText.addTextChangedListener(object : TextWatcher {
|
||||
override fun beforeTextChanged(charSequence: CharSequence, i: Int, i1: Int, i2: Int) {}
|
||||
override fun onTextChanged(input: CharSequence, i: Int, i1: Int, i2: Int) {
|
||||
updatePositiveButton()
|
||||
}
|
||||
override fun afterTextChanged(editable: Editable) {}
|
||||
})
|
||||
passwordEditText.setOnEditorActionListener { _, actionId, _ ->
|
||||
if (actionId != IME_ACTION_DONE) return@setOnEditorActionListener false
|
||||
sendPassword()
|
||||
true
|
||||
}
|
||||
passwordPrompt.setPositiveButton(R.string.open, null)
|
||||
passwordPrompt.setNegativeButton(R.string.cancel, null)
|
||||
val dialog = passwordPrompt.create()
|
||||
passwordPrompt.setCancelable(false)
|
||||
isCancelable = false
|
||||
dialog.setCanceledOnTouchOutside(false)
|
||||
dialog.window?.setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_VISIBLE)
|
||||
(requireActivity() as PdfViewer).passwordValidationViewModel.status.observe(
|
||||
this
|
||||
) {
|
||||
when (it) {
|
||||
PasswordStatus.Status.MissingPassword -> {
|
||||
passwordEditText.editableText.clear()
|
||||
passwordDialogFragmentBinding.title.setText(R.string.password_prompt_description)
|
||||
}
|
||||
PasswordStatus.Status.InvalidPassword -> {
|
||||
passwordEditText.editableText.clear()
|
||||
passwordDialogFragmentBinding.pdfPasswordTextInputLayout.error =
|
||||
"invalid password"
|
||||
}
|
||||
PasswordStatus.Status.Validated -> {
|
||||
//Activity will dismiss the dialog
|
||||
}
|
||||
else -> {
|
||||
throw NullPointerException("status shouldn't be null")
|
||||
}
|
||||
}
|
||||
}
|
||||
return dialog
|
||||
}
|
||||
|
||||
private fun updatePositiveButton() {
|
||||
passwordLayout.error = ""
|
||||
val btn = (dialog as AlertDialog).getButton(DialogInterface.BUTTON_POSITIVE)
|
||||
btn.isEnabled = passwordEditText.text?.isNotEmpty() ?: false
|
||||
}
|
||||
|
||||
private fun sendPassword() {
|
||||
val password = passwordEditText.text.toString()
|
||||
if (!TextUtils.isEmpty(password)) {
|
||||
(activity as PdfViewer).loadPdfWithPassword(password)
|
||||
}
|
||||
}
|
||||
|
||||
override fun onStart() {
|
||||
super.onStart()
|
||||
updatePositiveButton()
|
||||
passwordEditText.requestFocus()
|
||||
}
|
||||
|
||||
override fun onResume() {
|
||||
super.onResume()
|
||||
(dialog as AlertDialog).getButton(DialogInterface.BUTTON_POSITIVE).setOnClickListener {
|
||||
sendPassword()
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,27 @@
|
|||
package app.grapheneos.pdfviewer.viewModel
|
||||
|
||||
import androidx.lifecycle.MutableLiveData
|
||||
import androidx.lifecycle.ViewModel
|
||||
|
||||
class PasswordStatus : ViewModel() {
|
||||
|
||||
enum class Status {
|
||||
MissingPassword,
|
||||
InvalidPassword,
|
||||
Validated
|
||||
}
|
||||
|
||||
val status: MutableLiveData<Status> = MutableLiveData(Status.MissingPassword)
|
||||
|
||||
fun passwordMissing() {
|
||||
status.postValue(Status.MissingPassword)
|
||||
}
|
||||
|
||||
fun invalid() {
|
||||
status.postValue(Status.InvalidPassword)
|
||||
}
|
||||
|
||||
fun validated() {
|
||||
status.postValue(Status.Validated)
|
||||
}
|
||||
}
|
|
@ -0,0 +1,10 @@
|
|||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24"
|
||||
android:tint="?attr/colorControlNormal">
|
||||
<path
|
||||
android:fillColor="@android:color/white"
|
||||
android:pathData="M17,3L5,3c-1.11,0 -2,0.9 -2,2v14c0,1.1 0.89,2 2,2h14c1.1,0 2,-0.9 2,-2L21,7l-4,-4zM19,19L5,19L5,5h11.17L19,7.83L19,19zM12,12c-1.66,0 -3,1.34 -3,3s1.34,3 3,3 3,-1.34 3,-3 -1.34,-3 -3,-3zM6,6h9v4L6,10z"/>
|
||||
</vector>
|
|
@ -1,9 +0,0 @@
|
|||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24">
|
||||
<path
|
||||
android:fillColor="?attr/colorControlNormal"
|
||||
android:pathData="M15.5,14h-0.79l-0.28,-0.27c1.2,-1.4 1.82,-3.31 1.48,-5.34 -0.47,-2.78 -2.79,-5 -5.59,-5.34 -4.23,-0.52 -7.78,3.04 -7.27,7.27 0.34,2.8 2.56,5.12 5.34,5.59 2.03,0.34 3.94,-0.28 5.34,-1.48l0.27,0.28v0.79l4.26,4.25c0.41,0.41 1.07,0.41 1.48,0l0.01,-0.01c0.41,-0.41 0.41,-1.07 0,-1.48L15.5,14zM9.5,14C7.01,14 5,11.99 5,9.5S7.01,5 9.5,5 14,7.01 14,9.5 11.99,14 9.5,14zM9.5,7c-0.28,0 -0.5,0.22 -0.5,0.5L9,9L7.5,9c-0.28,0 -0.5,0.22 -0.5,0.5s0.22,0.5 0.5,0.5L9,10v1.5c0,0.28 0.22,0.5 0.5,0.5s0.5,-0.22 0.5,-0.5L10,10h1.5c0.28,0 0.5,-0.22 0.5,-0.5s-0.22,-0.5 -0.5,-0.5L10,9L10,7.5c0,-0.28 -0.22,-0.5 -0.5,-0.5z" />
|
||||
</vector>
|
|
@ -1,9 +0,0 @@
|
|||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24">
|
||||
<path
|
||||
android:fillColor="?attr/colorControlNormal"
|
||||
android:pathData="M15.5,14h-0.79l-0.28,-0.27c1.2,-1.4 1.82,-3.31 1.48,-5.34 -0.47,-2.78 -2.79,-5 -5.59,-5.34 -4.23,-0.52 -7.79,3.04 -7.27,7.27 0.34,2.8 2.56,5.12 5.34,5.59 2.03,0.34 3.94,-0.28 5.34,-1.48l0.27,0.28v0.79l4.26,4.25c0.41,0.41 1.07,0.41 1.48,0l0.01,-0.01c0.41,-0.41 0.41,-1.07 0,-1.48L15.5,14zM9.5,14C7.01,14 5,11.99 5,9.5S7.01,5 9.5,5 14,7.01 14,9.5 11.99,14 9.5,14zM7.5,9h4c0.28,0 0.5,0.22 0.5,0.5s-0.22,0.5 -0.5,0.5h-4c-0.28,0 -0.5,-0.22 -0.5,-0.5s0.22,-0.5 0.5,-0.5z" />
|
||||
</vector>
|
|
@ -0,0 +1,40 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical">
|
||||
|
||||
<com.google.android.material.textview.MaterialTextView
|
||||
android:id="@+id/title"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="24dp"
|
||||
android:layout_marginTop="24dp"
|
||||
android:layout_marginEnd="24dp"
|
||||
android:layout_marginBottom="20dp"
|
||||
android:text="@string/password_prompt_description"
|
||||
android:textColor="?android:attr/colorAccent"
|
||||
android:textSize="20sp" />
|
||||
|
||||
<com.google.android.material.textfield.TextInputLayout
|
||||
android:id="@+id/pdf_password_text_input_layout"
|
||||
style="@style/Widget.Material3.TextInputLayout.OutlinedBox"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
app:hintEnabled="false"
|
||||
app:passwordToggleEnabled="true"
|
||||
app:passwordToggleTint="?android:attr/colorAccent">
|
||||
|
||||
<com.google.android.material.textfield.TextInputEditText
|
||||
android:id="@+id/pdf_password_edit_text"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="24dp"
|
||||
android:layout_marginEnd="24dp"
|
||||
android:layout_marginBottom="24dp"
|
||||
android:hint="@string/password_prompt_hint"
|
||||
android:inputType="textPassword" />
|
||||
|
||||
</com.google.android.material.textfield.TextInputLayout>
|
||||
</LinearLayout>
|
|
@ -25,24 +25,6 @@
|
|||
android:title="@string/action_open"
|
||||
app:showAsAction="ifRoom" />
|
||||
|
||||
<item
|
||||
android:id="@+id/action_zoom_out"
|
||||
android:icon="@drawable/ic_zoom_out_24dp"
|
||||
android:title="@string/action_zoom_out"
|
||||
app:showAsAction="ifRoom" />
|
||||
|
||||
<item
|
||||
android:id="@+id/action_zoom_in"
|
||||
android:icon="@drawable/ic_zoom_in_24dp"
|
||||
android:title="@string/action_zoom_in"
|
||||
app:showAsAction="ifRoom" />
|
||||
|
||||
<item
|
||||
android:id="@+id/action_share"
|
||||
android:icon="@drawable/ic_share_24dp"
|
||||
android:title="@string/action_share"
|
||||
app:showAsAction="ifRoom" />
|
||||
|
||||
<item
|
||||
android:id="@+id/action_first"
|
||||
android:icon="@drawable/ic_first_page_24dp"
|
||||
|
@ -73,6 +55,18 @@
|
|||
android:title="@string/action_rotate_counterclockwise"
|
||||
app:showAsAction="ifRoom" />
|
||||
|
||||
<item
|
||||
android:id="@+id/action_share"
|
||||
android:icon="@drawable/ic_share_24dp"
|
||||
android:title="@string/action_share"
|
||||
app:showAsAction="ifRoom" />
|
||||
|
||||
<item
|
||||
android:id="@+id/action_save_as"
|
||||
android:icon="@drawable/ic_save_24dp"
|
||||
android:title="@string/action_save_as"
|
||||
app:showAsAction="never" />
|
||||
|
||||
<item
|
||||
android:id="@+id/action_view_document_properties"
|
||||
android:title="@string/action_view_document_properties"
|
||||
|
|
|
@ -2,4 +2,5 @@
|
|||
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<background android:drawable="@color/ic_launcher_background"/>
|
||||
<foreground android:drawable="@drawable/ic_launcher_foreground"/>
|
||||
<monochrome android:drawable="@drawable/ic_launcher_foreground" />
|
||||
</adaptive-icon>
|
|
@ -1,5 +0,0 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<background android:drawable="@color/ic_launcher_background"/>
|
||||
<foreground android:drawable="@drawable/ic_launcher_foreground"/>
|
||||
</adaptive-icon>
|
|
@ -1,5 +1,5 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<resources xmlns:tools="http://schemas.android.com/tools">
|
||||
<string name="app_name">PDF Viewer</string>
|
||||
<!--<string name="action_settings">Settings</string>-->
|
||||
<string name="action_previous">Previous page</string>
|
||||
|
@ -7,11 +7,11 @@
|
|||
<string name="action_open">Open document</string>
|
||||
<string name="action_first">First page</string>
|
||||
<string name="action_last">Last page</string>
|
||||
<string name="action_zoom_out">Zoom out</string>
|
||||
<string name="action_zoom_in">Zoom in</string>
|
||||
<string name="action_jump_to_page">Jump to page</string>
|
||||
<string name="action_rotate_clockwise">Rotate clockwise</string>
|
||||
<string name="action_rotate_counterclockwise">Rotate counterclockwise</string>
|
||||
<string name="action_jump_to_page">Jump to page</string>
|
||||
<string name="action_share">Share</string>
|
||||
<string name="action_save_as">Save as</string>
|
||||
<string name="action_view_document_properties">Properties</string>
|
||||
|
||||
<string name="document_properties_invalid_date">Invalid date</string>
|
||||
|
@ -19,9 +19,14 @@
|
|||
|
||||
<string name="invalid_mime_type">Cannot open file with invalid MIME type</string>
|
||||
<string name="legacy_file_uri">Cannot open legacy file paths from insecure apps</string>
|
||||
<string name="io_error">Received I/O error trying to open content</string>
|
||||
<string name="error_while_opening">Error encountered trying to open content</string>
|
||||
<string name="error_while_saving">Error encountered while saving</string>
|
||||
|
||||
<string name="webview_out_of_date_title">WebView out-of-date</string>
|
||||
<string name="webview_out_of_date_message">Your current WebView version is %d. The WebView should be at least version %d for the PDF Viewer to work.</string>
|
||||
<string name="action_share">Share</string>
|
||||
<string name="webview_out_of_date_message" tools:ignore="PluralsCandidate">Your current WebView version is %1$d. The WebView should be at least version %2$d for the PDF Viewer to work.</string>
|
||||
|
||||
<string name="password_prompt_hint">Password</string>
|
||||
<string name="password_prompt_description">Enter the password to decrypt this PDF file</string>
|
||||
<string name="open">Open</string>
|
||||
<string name="cancel">Cancel</string>
|
||||
</resources>
|
||||
|
|
|
@ -1,11 +1,17 @@
|
|||
buildscript {
|
||||
repositories {
|
||||
google()
|
||||
mavenCentral()
|
||||
// dependabot cannot handle google()
|
||||
maven {
|
||||
url = uri("https://dl.google.com/dl/android/maven2")
|
||||
}
|
||||
// dependabot cannot handle mavenCentral()
|
||||
maven {
|
||||
url = uri("https://repo.maven.apache.org/maven2")
|
||||
}
|
||||
}
|
||||
dependencies {
|
||||
classpath("com.android.tools.build:gradle:7.1.2")
|
||||
classpath("org.jetbrains.kotlin:kotlin-gradle-plugin:1.6.10")
|
||||
classpath("com.android.tools.build:gradle:7.3.0")
|
||||
classpath("org.jetbrains.kotlin:kotlin-gradle-plugin:1.7.10")
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Binary file not shown.
|
@ -1,6 +1,6 @@
|
|||
distributionBase=GRADLE_USER_HOME
|
||||
distributionPath=wrapper/dists
|
||||
distributionSha256Sum=e5444a57cda4a95f90b0c9446a9e1b47d3d7f69057765bfb54bd4f482542d548
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-7.4.1-bin.zip
|
||||
distributionSha256Sum=f6b8596b10cce501591e92f229816aa4046424f3b24d771751b06779d58c8ec4
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-7.5.1-bin.zip
|
||||
zipStoreBase=GRADLE_USER_HOME
|
||||
zipStorePath=wrapper/dists
|
||||
|
|
|
@ -205,6 +205,12 @@ set -- \
|
|||
org.gradle.wrapper.GradleWrapperMain \
|
||||
"$@"
|
||||
|
||||
# Stop when "xargs" is not available.
|
||||
if ! command -v xargs >/dev/null 2>&1
|
||||
then
|
||||
die "xargs is not available"
|
||||
fi
|
||||
|
||||
# Use "xargs" to parse quoted args.
|
||||
#
|
||||
# With -n1 it outputs one arg per line, with the quotes and backslashes removed.
|
||||
|
|
|
@ -14,7 +14,7 @@
|
|||
@rem limitations under the License.
|
||||
@rem
|
||||
|
||||
@if "%DEBUG%" == "" @echo off
|
||||
@if "%DEBUG%"=="" @echo off
|
||||
@rem ##########################################################################
|
||||
@rem
|
||||
@rem Gradle startup script for Windows
|
||||
|
@ -25,7 +25,7 @@
|
|||
if "%OS%"=="Windows_NT" setlocal
|
||||
|
||||
set DIRNAME=%~dp0
|
||||
if "%DIRNAME%" == "" set DIRNAME=.
|
||||
if "%DIRNAME%"=="" set DIRNAME=.
|
||||
set APP_BASE_NAME=%~n0
|
||||
set APP_HOME=%DIRNAME%
|
||||
|
||||
|
@ -40,7 +40,7 @@ if defined JAVA_HOME goto findJavaFromJavaHome
|
|||
|
||||
set JAVA_EXE=java.exe
|
||||
%JAVA_EXE% -version >NUL 2>&1
|
||||
if "%ERRORLEVEL%" == "0" goto execute
|
||||
if %ERRORLEVEL% equ 0 goto execute
|
||||
|
||||
echo.
|
||||
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
|
||||
|
@ -75,13 +75,15 @@ set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
|
|||
|
||||
:end
|
||||
@rem End local scope for the variables with windows NT shell
|
||||
if "%ERRORLEVEL%"=="0" goto mainEnd
|
||||
if %ERRORLEVEL% equ 0 goto mainEnd
|
||||
|
||||
:fail
|
||||
rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
|
||||
rem the _cmd.exe /c_ return code!
|
||||
if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
|
||||
exit /b 1
|
||||
set EXIT_CODE=%ERRORLEVEL%
|
||||
if %EXIT_CODE% equ 0 set EXIT_CODE=1
|
||||
if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE%
|
||||
exit /b %EXIT_CODE%
|
||||
|
||||
:mainEnd
|
||||
if "%OS%"=="Windows_NT" endlocal
|
||||
|
|
|
@ -1 +1 @@
|
|||
Subproject commit 070a365be5a7579f4ddd5a9a2d4efcd281c2d64f
|
||||
Subproject commit cc3d3bf299ae11f8f72ae8d64cbf19b340f9a996
|
Loading…
Reference in New Issue