Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
162b88915e | ||
|
|
d014b6947c | ||
|
|
a6188964c9 | ||
|
|
722fbec72c | ||
|
|
22190fb686 | ||
|
|
49ea70c839 | ||
|
|
c655e7e1c9 | ||
|
|
d13cd1e07f | ||
|
|
7365fd0448 | ||
|
|
f1febca312 | ||
|
|
dbf67404c0 | ||
|
|
8cfe8c4b80 | ||
|
|
674f53315f | ||
|
|
e51cd6b90d | ||
|
|
a44f12b2e0 | ||
|
|
a2552ed5b9 | ||
|
|
763c007950 |
No files matched your search
@@ -34,9 +34,11 @@ with Material Design 3 and Dynamic Color Support
|
||||
|
||||
# Download
|
||||
|
||||
[Github 下载](https://github.com/Ehviewer-Overhauled/Ehviewer/releases)
|
||||
<a href="https://github.com/Ehviewer-Overhauled/Ehviewer/releases"><img alt="Get it on Google Play" src="art/get-it-on-github.svg" width="200px"/></a>
|
||||
|
||||
[CI 版本下载(需登录)](https://github.com/Ehviewer-Overhauled/Ehviewer/actions/workflows/ci.yml)
|
||||
App 分为 1.8 与 1.7 两个版本。1.8 版本适配 Android 12 及以上系统,为开发主线;1.7 版本适配 Android 11 及以下版本,削减了 Android 12 及以上系统的独有功能,使其能在低版本 Android 上正常工作
|
||||
|
||||
App is divided into two versions: 1.7 and 1.8 . Version 1.8 support Android 12 and above, also the develop mainline. Version 1.7 support Android 11 and below, drop down some spicetify functions for Android 12 to make app useable on lower Android System
|
||||
|
||||
# Screenshot
|
||||
|
||||
|
||||
+4
-5
@@ -34,8 +34,8 @@ android {
|
||||
applicationId "moe.tarsin.ehviewer"
|
||||
minSdkVersion 31
|
||||
targetSdkVersion 33
|
||||
versionCode 180001
|
||||
versionName "1.8.0.1"
|
||||
versionCode 180004
|
||||
versionName "1.8.0.4"
|
||||
resConfigs 'zh', 'zh-rCN', 'zh-rHK', 'zh-rTW', 'es', 'ja', 'ko', 'fr', 'de', 'th'
|
||||
}
|
||||
|
||||
@@ -107,7 +107,7 @@ dependencies {
|
||||
implementation "androidx.biometric:biometric-ktx:1.2.0-alpha04"
|
||||
implementation "androidx.browser:browser:1.4.0"
|
||||
|
||||
def collection_version = "1.3.0-alpha01"
|
||||
def collection_version = "1.3.0-alpha02"
|
||||
implementation "androidx.collection:collection:$collection_version"
|
||||
implementation "androidx.collection:collection-ktx:$collection_version"
|
||||
|
||||
@@ -122,7 +122,7 @@ dependencies {
|
||||
implementation "androidx.documentfile:documentfile:1.1.0-alpha01"
|
||||
implementation "androidx.dynamicanimation:dynamicanimation:1.1.0-alpha03"
|
||||
|
||||
def fragment_version = "1.5.0"
|
||||
def fragment_version = "1.5.1"
|
||||
implementation "androidx.fragment:fragment:$fragment_version"
|
||||
implementation "androidx.fragment:fragment-ktx:$fragment_version"
|
||||
|
||||
@@ -148,7 +148,6 @@ dependencies {
|
||||
|
||||
implementation 'com.drakeet.drawer:drawer:1.0.3'
|
||||
implementation 'com.google.android.material:material:1.7.0-alpha03'
|
||||
implementation 'com.getkeepsafe.taptargetview:taptargetview:1.13.3'
|
||||
implementation 'com.h6ah4i.android.widget.advrecyclerview:advrecyclerview:1.0.0'
|
||||
implementation 'com.squareup.okhttp3:okhttp:5.0.0-alpha.10'
|
||||
implementation 'dev.rikka.rikkax.core:core-ktx:1.4.1'
|
||||
|
||||
@@ -26,11 +26,12 @@
|
||||
<uses-permission android:name="android.permission.INTERNET" />
|
||||
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
|
||||
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
|
||||
|
||||
|
||||
<!-- Required to maintain app compatibility. -->
|
||||
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"
|
||||
android:maxSdkVersion="32" />
|
||||
|
||||
<uses-permission
|
||||
android:name="android.permission.READ_EXTERNAL_STORAGE"
|
||||
android:maxSdkVersion="32" />
|
||||
|
||||
<uses-feature
|
||||
android:glEsVersion="0x00020000"
|
||||
android:required="true" />
|
||||
|
||||
@@ -167,6 +167,7 @@ public final class DiskLruCache implements Closeable {
|
||||
* its sequence number is not equal to its entry's sequence number.
|
||||
*/
|
||||
private long nextSequenceNumber = 0;
|
||||
|
||||
private DiskLruCache(File directory, int appVersion, int valueCount, long maxSize) {
|
||||
this.directory = directory;
|
||||
this.appVersion = appVersion;
|
||||
@@ -175,21 +176,7 @@ public final class DiskLruCache implements Closeable {
|
||||
this.journalFileBackup = new File(directory, JOURNAL_FILE_BACKUP);
|
||||
this.valueCount = valueCount;
|
||||
this.maxSize = maxSize;
|
||||
} private final Callable<Void> cleanupCallable = new Callable<>() {
|
||||
public Void call() throws Exception {
|
||||
synchronized (DiskLruCache.this) {
|
||||
if (journalWriter == null) {
|
||||
return null; // Closed.
|
||||
}
|
||||
trimToSize();
|
||||
if (journalRebuildRequired()) {
|
||||
rebuildJournal();
|
||||
redundantOpCount = 0;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Opens the cache in {@code directory}, creating a cache if none exists
|
||||
@@ -244,7 +231,21 @@ public final class DiskLruCache implements Closeable {
|
||||
cache = new DiskLruCache(directory, appVersion, valueCount, maxSize);
|
||||
cache.rebuildJournal();
|
||||
return cache;
|
||||
}
|
||||
} private final Callable<Void> cleanupCallable = new Callable<>() {
|
||||
public Void call() throws Exception {
|
||||
synchronized (DiskLruCache.this) {
|
||||
if (journalWriter == null) {
|
||||
return null; // Closed.
|
||||
}
|
||||
trimToSize();
|
||||
if (journalRebuildRequired()) {
|
||||
rebuildJournal();
|
||||
redundantOpCount = 0;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
};
|
||||
|
||||
private static void deleteIfExists(File file) throws IOException {
|
||||
if (file.exists() && !file.delete()) {
|
||||
|
||||
@@ -16,8 +16,6 @@
|
||||
|
||||
package com.hippo.ehviewer;
|
||||
|
||||
import android.os.ParcelFileDescriptor;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
@@ -27,7 +25,6 @@ import com.hippo.streampipe.InputStreamPipe;
|
||||
|
||||
import java.io.FileInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
|
||||
public class ImageBitmapHelper implements ValueHelper<ImageBitmap> {
|
||||
|
||||
|
||||
@@ -34,10 +34,6 @@ import com.hippo.unifile.UniFile;
|
||||
import com.hippo.yorozuya.thread.PVLock;
|
||||
import com.hippo.yorozuya.thread.PriorityThread;
|
||||
|
||||
import java.io.FileDescriptor;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.Iterator;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
|
||||
@@ -259,7 +259,7 @@ public class DirGalleryProvider extends GalleryProvider2 implements Runnable {
|
||||
InputStream is = null;
|
||||
try {
|
||||
is = files[index].openInputStream();
|
||||
Image image = Image.decode(((FileInputStream)is).getFD(), true);
|
||||
Image image = Image.decode(((FileInputStream) is).getFD(), true);
|
||||
mDecodingIndex.lazySet(GalleryPageView.INVALID_INDEX);
|
||||
if (image != null) {
|
||||
notifyPageSucceed(index, image);
|
||||
|
||||
@@ -50,7 +50,7 @@ class VersionPreference @JvmOverloads constructor(
|
||||
|
||||
inner class NativeLibInfo {
|
||||
private var message: String = ""
|
||||
fun addLib(libname:String, libversion:String): NativeLibInfo {
|
||||
fun addLib(libname: String, libversion: String): NativeLibInfo {
|
||||
message = "$message$libname $libversion\n"
|
||||
return this
|
||||
}
|
||||
|
||||
@@ -1678,10 +1678,9 @@ public final class SpiderQueen implements Runnable {
|
||||
|
||||
if (is != null) {
|
||||
try {
|
||||
image = Image.decode(((FileInputStream)is).getFD(), true);
|
||||
image = Image.decode(((FileInputStream) is).getFD(), true);
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
image = null;
|
||||
} finally {
|
||||
try {
|
||||
is.close();
|
||||
|
||||
@@ -226,6 +226,9 @@ public class GalleryActivity extends EhActivity implements SeekBar.OnSeekBarChan
|
||||
private int mSize;
|
||||
private int mCurrentIndex;
|
||||
private int mSavingPage = -1;
|
||||
private EditTextDialogBuilder builder;
|
||||
private boolean dialogShown = false;
|
||||
private AlertDialog dialog;
|
||||
|
||||
private void buildProvider() {
|
||||
if (mGalleryProvider != null) {
|
||||
@@ -287,7 +290,16 @@ public class GalleryActivity extends EhActivity implements SeekBar.OnSeekBarChan
|
||||
}
|
||||
outState.putInt(KEY_PAGE, mPage);
|
||||
outState.putInt(KEY_CURRENT_INDEX, mCurrentIndex);
|
||||
}
|
||||
} ActivityResultLauncher<String> requestStoragePermissionLauncher = registerForActivityResult(
|
||||
new ActivityResultContracts.RequestPermission(),
|
||||
result -> {
|
||||
if (result && mSavingPage != -1) {
|
||||
saveImage(mSavingPage);
|
||||
} else {
|
||||
Toast.makeText(this, R.string.error_cant_save_image, Toast.LENGTH_SHORT).show();
|
||||
}
|
||||
mSavingPage = -1;
|
||||
});
|
||||
|
||||
@Override
|
||||
protected void attachBaseContext(@NonNull Context newBase) {
|
||||
@@ -477,16 +489,7 @@ public class GalleryActivity extends EhActivity implements SeekBar.OnSeekBarChan
|
||||
FrameLayout mainLayout = (FrameLayout) ViewUtils.$$(this, R.id.main);
|
||||
mainLayout.addView(new GalleryGuideView(this));
|
||||
}
|
||||
} ActivityResultLauncher<String> requestStoragePermissionLauncher = registerForActivityResult(
|
||||
new ActivityResultContracts.RequestPermission(),
|
||||
result -> {
|
||||
if (result && mSavingPage != -1) {
|
||||
saveImage(mSavingPage);
|
||||
} else {
|
||||
Toast.makeText(this, R.string.error_cant_save_image, Toast.LENGTH_SHORT).show();
|
||||
}
|
||||
mSavingPage = -1;
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onDestroy() {
|
||||
@@ -1046,6 +1049,66 @@ public class GalleryActivity extends EhActivity implements SeekBar.OnSeekBarChan
|
||||
}
|
||||
}
|
||||
|
||||
private void showPasswdDialog() {
|
||||
if (!dialogShown) {
|
||||
dialogShown = true;
|
||||
dialog.show();
|
||||
if (dialog.getButton(AlertDialog.BUTTON_POSITIVE) != null) {
|
||||
dialog.getButton(AlertDialog.BUTTON_POSITIVE).setOnClickListener(v -> {
|
||||
GalleryActivity.this.onProvidePasswd();
|
||||
});
|
||||
}
|
||||
dialog.setOnCancelListener(v -> finish());
|
||||
}
|
||||
}
|
||||
|
||||
private void onProvidePasswd() {
|
||||
String passwd = builder.getText();
|
||||
if (passwd.isEmpty())
|
||||
builder.setError(getString(R.string.passwd_cannot_be_empty));
|
||||
else {
|
||||
ArchiveGalleryProvider.passwd = passwd;
|
||||
ArchiveGalleryProvider.pv.v();
|
||||
}
|
||||
}
|
||||
|
||||
private void onPasswdWrong() {
|
||||
builder.setError(getString(R.string.passwd_wrong));
|
||||
}
|
||||
|
||||
private void onPasswdCorrect() {
|
||||
dialog.dismiss();
|
||||
}
|
||||
|
||||
private static class ShowPasswdDialogHandler extends Handler {
|
||||
|
||||
//弱引用持有HandlerActivity , GC 回收时会被回收掉
|
||||
private final WeakReference<GalleryActivity> weakReference;
|
||||
|
||||
public ShowPasswdDialogHandler(GalleryActivity activity) {
|
||||
this.weakReference = new WeakReference(activity);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleMessage(Message msg) {
|
||||
GalleryActivity activity = weakReference.get();
|
||||
super.handleMessage(msg);
|
||||
if (null != activity) {
|
||||
switch (msg.what) {
|
||||
case 0:
|
||||
activity.showPasswdDialog();
|
||||
break;
|
||||
case 1:
|
||||
activity.onPasswdWrong();
|
||||
break;
|
||||
case 2:
|
||||
activity.onPasswdCorrect();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private class GalleryMenuHelper implements DialogInterface.OnClickListener {
|
||||
|
||||
private final View mView;
|
||||
@@ -1306,69 +1369,5 @@ public class GalleryActivity extends EhActivity implements SeekBar.OnSeekBarChan
|
||||
}
|
||||
}
|
||||
|
||||
private EditTextDialogBuilder builder;
|
||||
|
||||
private boolean dialogShown = false;
|
||||
|
||||
private AlertDialog dialog;
|
||||
|
||||
private void showPasswdDialog() {
|
||||
if (!dialogShown) {
|
||||
dialogShown = true;
|
||||
dialog.show();
|
||||
if (dialog.getButton(AlertDialog.BUTTON_POSITIVE) != null) {
|
||||
dialog.getButton(AlertDialog.BUTTON_POSITIVE).setOnClickListener(v -> {
|
||||
GalleryActivity.this.onProvidePasswd();
|
||||
});
|
||||
}
|
||||
dialog.setOnCancelListener(v -> finish());
|
||||
}
|
||||
}
|
||||
|
||||
private void onProvidePasswd() {
|
||||
String passwd = builder.getText();
|
||||
if (passwd.isEmpty())
|
||||
builder.setError(getString(R.string.passwd_cannot_be_empty));
|
||||
else {
|
||||
ArchiveGalleryProvider.passwd = passwd;
|
||||
ArchiveGalleryProvider.pv.v();
|
||||
}
|
||||
}
|
||||
|
||||
private void onPasswdWrong() {
|
||||
builder.setError(getString(R.string.passwd_wrong));
|
||||
}
|
||||
|
||||
private void onPasswdCorrect() {
|
||||
dialog.dismiss();
|
||||
}
|
||||
|
||||
private static class ShowPasswdDialogHandler extends Handler {
|
||||
|
||||
//弱引用持有HandlerActivity , GC 回收时会被回收掉
|
||||
private final WeakReference<GalleryActivity> weakReference;
|
||||
|
||||
public ShowPasswdDialogHandler(GalleryActivity activity) {
|
||||
this.weakReference = new WeakReference(activity);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleMessage(Message msg) {
|
||||
GalleryActivity activity = weakReference.get();
|
||||
super.handleMessage(msg);
|
||||
if (null != activity) {
|
||||
switch (msg.what) {
|
||||
case 0:
|
||||
activity.showPasswdDialog();
|
||||
break;
|
||||
case 1:
|
||||
activity.onPasswdWrong();
|
||||
break;
|
||||
case 2:
|
||||
activity.onPasswdCorrect();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -22,7 +22,6 @@ import android.content.res.Resources;
|
||||
import android.net.Uri;
|
||||
import android.os.Build;
|
||||
import android.os.Bundle;
|
||||
import android.provider.Settings;
|
||||
|
||||
import androidx.activity.result.ActivityResultLauncher;
|
||||
import androidx.activity.result.contract.ActivityResultContracts;
|
||||
|
||||
@@ -55,8 +55,6 @@ import androidx.recyclerview.widget.RecyclerView;
|
||||
import androidx.recyclerview.widget.SimpleItemAnimator;
|
||||
import androidx.recyclerview.widget.StaggeredGridLayoutManager;
|
||||
|
||||
import com.getkeepsafe.taptargetview.TapTarget;
|
||||
import com.getkeepsafe.taptargetview.TapTargetView;
|
||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder;
|
||||
import com.google.android.material.floatingactionbutton.FloatingActionButton;
|
||||
import com.h6ah4i.android.widget.advrecyclerview.animator.DraggableItemAnimator;
|
||||
@@ -390,90 +388,9 @@ public class DownloadsScene extends ToolbarScene
|
||||
|
||||
updateView();
|
||||
|
||||
guide();
|
||||
|
||||
return view;
|
||||
}
|
||||
|
||||
private void guide() {
|
||||
if (Settings.getGuideDownloadThumb() && null != mRecyclerView) {
|
||||
mRecyclerView.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
|
||||
@Override
|
||||
public void onGlobalLayout() {
|
||||
if (Settings.getGuideDownloadThumb()) {
|
||||
guideDownloadThumb();
|
||||
}
|
||||
if (null != mRecyclerView) {
|
||||
ViewUtils.removeOnGlobalLayoutListener(mRecyclerView.getViewTreeObserver(), this);
|
||||
}
|
||||
}
|
||||
});
|
||||
} else {
|
||||
guideDownloadLabels();
|
||||
}
|
||||
}
|
||||
|
||||
private void guideDownloadThumb() {
|
||||
MainActivity activity = getMainActivity();
|
||||
if (null == activity || !Settings.getGuideDownloadThumb() || null == mLayoutManager || null == mRecyclerView) {
|
||||
guideDownloadLabels();
|
||||
return;
|
||||
}
|
||||
int position = mLayoutManager.findFirstCompletelyVisibleItemPositions(null)[0];
|
||||
if (position < 0) {
|
||||
guideDownloadLabels();
|
||||
return;
|
||||
}
|
||||
RecyclerView.ViewHolder holder = mRecyclerView.findViewHolderForAdapterPosition(position);
|
||||
if (null == holder) {
|
||||
guideDownloadLabels();
|
||||
return;
|
||||
}
|
||||
|
||||
TapTargetView.showFor(requireActivity(),
|
||||
TapTarget.forView(((DownloadHolder) holder).thumb,
|
||||
getString(R.string.guide_download_thumb_title),
|
||||
getString(R.string.guide_download_thumb_text))
|
||||
.transparentTarget(true),
|
||||
new TapTargetView.Listener() {
|
||||
@Override
|
||||
public void onTargetDismissed(TapTargetView view, boolean userInitiated) {
|
||||
super.onTargetDismissed(view, userInitiated);
|
||||
Settings.putGuideDownloadThumb(false);
|
||||
guideDownloadLabels();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void guideDownloadLabels() {
|
||||
MainActivity activity = getMainActivity();
|
||||
if (null == activity || !Settings.getGuideDownloadLabels()) {
|
||||
return;
|
||||
}
|
||||
|
||||
Display display = activity.getWindowManager().getDefaultDisplay();
|
||||
Point point = new Point();
|
||||
display.getSize(point);
|
||||
Rect bounds = new Rect(point.x + LayoutUtils.dp2pix(requireContext(), 20),
|
||||
point.y / 3 + LayoutUtils.dp2pix(requireContext(), 20),
|
||||
point.x - LayoutUtils.dp2pix(requireContext(), 20),
|
||||
point.y / 3 - LayoutUtils.dp2pix(requireContext(), 20));
|
||||
|
||||
TapTargetView.showFor(requireActivity(),
|
||||
TapTarget.forBounds(bounds,
|
||||
getString(R.string.guide_download_labels_title),
|
||||
getString(R.string.guide_download_labels_text))
|
||||
.transparentTarget(true),
|
||||
new TapTargetView.Listener() {
|
||||
@Override
|
||||
public void onTargetDismissed(TapTargetView view, boolean userInitiated) {
|
||||
super.onTargetClick(view);
|
||||
Settings.puttGuideDownloadLabels(false);
|
||||
openDrawer(Gravity.RIGHT);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
|
||||
super.onViewCreated(view, savedInstanceState);
|
||||
|
||||
@@ -45,8 +45,6 @@ import androidx.drawerlayout.widget.DrawerLayout;
|
||||
import androidx.recyclerview.widget.LinearLayoutManager;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
|
||||
import com.getkeepsafe.taptargetview.TapTarget;
|
||||
import com.getkeepsafe.taptargetview.TapTargetView;
|
||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder;
|
||||
import com.google.android.material.floatingactionbutton.FloatingActionButton;
|
||||
import com.hippo.annotation.Implemented;
|
||||
@@ -311,40 +309,9 @@ public class FavoritesScene extends BaseScene implements
|
||||
mHelper.firstRefresh();
|
||||
}
|
||||
|
||||
guideCollections();
|
||||
|
||||
return view;
|
||||
}
|
||||
|
||||
private void guideCollections() {
|
||||
Activity activity = getMainActivity();
|
||||
if (null == activity || !Settings.getGuideCollections()) {
|
||||
return;
|
||||
}
|
||||
|
||||
Display display = activity.getWindowManager().getDefaultDisplay();
|
||||
Point point = new Point();
|
||||
display.getSize(point);
|
||||
Rect bounds = new Rect(point.x + LayoutUtils.dp2pix(requireContext(), 20),
|
||||
point.y / 3 + LayoutUtils.dp2pix(requireContext(), 20),
|
||||
point.x - LayoutUtils.dp2pix(requireContext(), 20),
|
||||
point.y / 3 - LayoutUtils.dp2pix(requireContext(), 20));
|
||||
|
||||
TapTargetView.showFor(requireActivity(),
|
||||
TapTarget.forBounds(bounds,
|
||||
getString(R.string.guide_collections_title),
|
||||
getString(R.string.guide_collections_text))
|
||||
.transparentTarget(true),
|
||||
new TapTargetView.Listener() {
|
||||
@Override
|
||||
public void onTargetDismissed(TapTargetView view, boolean userInitiated) {
|
||||
super.onTargetClick(view);
|
||||
Settings.putGuideCollections(false);
|
||||
openDrawer(Gravity.RIGHT);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// keyword of mUrlBuilder, fav cat of mUrlBuilder, mFavCatArray.
|
||||
// They changed, call it
|
||||
private void updateSearchBar() {
|
||||
|
||||
@@ -59,8 +59,6 @@ import androidx.drawerlayout.widget.DrawerLayout;
|
||||
import androidx.recyclerview.widget.LinearLayoutManager;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
|
||||
import com.getkeepsafe.taptargetview.TapTarget;
|
||||
import com.getkeepsafe.taptargetview.TapTargetView;
|
||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder;
|
||||
import com.google.android.material.floatingactionbutton.FloatingActionButton;
|
||||
import com.h6ah4i.android.widget.advrecyclerview.animator.DraggableItemAnimator;
|
||||
@@ -634,40 +632,9 @@ public final class GalleryListScene extends BaseScene
|
||||
mHelper.firstRefresh();
|
||||
}
|
||||
|
||||
guideQuickSearch();
|
||||
|
||||
return view;
|
||||
}
|
||||
|
||||
private void guideQuickSearch() {
|
||||
Activity activity = getMainActivity();
|
||||
if (null == activity || !Settings.getGuideQuickSearch()) {
|
||||
return;
|
||||
}
|
||||
|
||||
Display display = activity.getWindowManager().getDefaultDisplay();
|
||||
Point point = new Point();
|
||||
display.getSize(point);
|
||||
Rect bounds = new Rect(point.x + LayoutUtils.dp2pix(requireContext(), 20),
|
||||
point.y / 3 + LayoutUtils.dp2pix(requireContext(), 20),
|
||||
point.x - LayoutUtils.dp2pix(requireContext(), 20),
|
||||
point.y / 3 - LayoutUtils.dp2pix(requireContext(), 20));
|
||||
|
||||
TapTargetView.showFor(requireActivity(),
|
||||
TapTarget.forBounds(bounds,
|
||||
getString(R.string.guide_quick_search_title),
|
||||
getString(R.string.guide_quick_search_text))
|
||||
.transparentTarget(true),
|
||||
new TapTargetView.Listener() {
|
||||
@Override
|
||||
public void onTargetDismissed(TapTargetView view, boolean userInitiated) {
|
||||
super.onTargetClick(view);
|
||||
Settings.putGuideQuickSearch(false);
|
||||
openDrawer(Gravity.RIGHT);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDestroyView() {
|
||||
super.onDestroyView();
|
||||
|
||||
@@ -57,6 +57,7 @@ public abstract class GalleryProvider {
|
||||
public void stop() {
|
||||
OSUtils.checkMainLoop();
|
||||
mImageCache.evictAll();
|
||||
Image.lazyEvictAll();
|
||||
}
|
||||
|
||||
public void setGLRoot(GLRoot glRoot) {
|
||||
@@ -245,18 +246,14 @@ public abstract class GalleryProvider {
|
||||
}
|
||||
|
||||
public void add(Integer key, ImageWrapper value) {
|
||||
if (value.getFormat() != Image.FORMAT_ANIMATED && value.obtain()) {
|
||||
put(key, value);
|
||||
}
|
||||
if (value.getFormat() != Image.FORMAT_ANIMATED)
|
||||
if (value.obtain())
|
||||
put(key, value);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected int sizeOf(Integer key, ImageWrapper value) {
|
||||
int size = value.getWidth() * value.getHeight() * 4;
|
||||
if (value.getFormat() == Image.FORMAT_ANIMATED) {
|
||||
size *= 5;
|
||||
}
|
||||
return size;
|
||||
return value.getWidth() * value.getHeight() * 4;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -33,6 +33,7 @@ final class DocumentsContractApi21 {
|
||||
private static final String TAG = DocumentsContractApi21.class.getSimpleName();
|
||||
private static final String PATH_DOCUMENT = "document";
|
||||
private static final String PATH_TREE = "tree";
|
||||
|
||||
private DocumentsContractApi21() {
|
||||
}
|
||||
|
||||
|
||||
@@ -41,6 +41,7 @@ class FileDescriptorRandomAccessFile implements UniRandomAccessFile {
|
||||
private final int flushAfterWrite;
|
||||
private final Object closeLock = new Object();
|
||||
private volatile boolean closed = false;
|
||||
|
||||
private FileDescriptorRandomAccessFile(ParcelFileDescriptor pfd, FileDescriptor fd, String mode) {
|
||||
this.pfd = pfd;
|
||||
this.fd = fd;
|
||||
|
||||
@@ -82,6 +82,13 @@ public class BatteryView extends AppCompatTextView {
|
||||
}
|
||||
mCurrentColor = color;
|
||||
super.setTextColor(color);
|
||||
}
|
||||
|
||||
private void startCharger() {
|
||||
if (!mIsChargerWorking) {
|
||||
getHandler().post(mCharger);
|
||||
mIsChargerWorking = true;
|
||||
}
|
||||
} private final Runnable mCharger = new Runnable() {
|
||||
|
||||
private int level = 0;
|
||||
@@ -97,13 +104,6 @@ public class BatteryView extends AppCompatTextView {
|
||||
}
|
||||
};
|
||||
|
||||
private void startCharger() {
|
||||
if (!mIsChargerWorking) {
|
||||
getHandler().post(mCharger);
|
||||
mIsChargerWorking = true;
|
||||
}
|
||||
}
|
||||
|
||||
private void stopCharger() {
|
||||
if (mIsChargerWorking) {
|
||||
getHandler().removeCallbacks(mCharger);
|
||||
@@ -145,6 +145,7 @@ public class BatteryView extends AppCompatTextView {
|
||||
|
||||
|
||||
|
||||
|
||||
private final BroadcastReceiver mIntentReceiver = new BroadcastReceiver() {
|
||||
|
||||
@Override
|
||||
|
||||
@@ -97,6 +97,10 @@ public class TextClock extends AppCompatTextView {
|
||||
} else {
|
||||
mTime = Calendar.getInstance();
|
||||
}
|
||||
}
|
||||
|
||||
public CharSequence getFormat12Hour() {
|
||||
return mFormat12;
|
||||
} private final Runnable mTicker = new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
@@ -109,10 +113,6 @@ public class TextClock extends AppCompatTextView {
|
||||
}
|
||||
};
|
||||
|
||||
public CharSequence getFormat12Hour() {
|
||||
return mFormat12;
|
||||
}
|
||||
|
||||
public void setFormat12Hour(CharSequence format) {
|
||||
mFormat12 = format;
|
||||
|
||||
@@ -144,19 +144,7 @@ public class TextClock extends AppCompatTextView {
|
||||
|
||||
createTime(timeZone);
|
||||
onTimeChanged();
|
||||
} private final ContentObserver mFormatChangeObserver = new ContentObserver(new Handler()) {
|
||||
@Override
|
||||
public void onChange(boolean selfChange) {
|
||||
chooseFormat();
|
||||
onTimeChanged();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onChange(boolean selfChange, Uri uri) {
|
||||
chooseFormat();
|
||||
onTimeChanged();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Selects either one of {@link #getFormat12Hour()} or {@link #getFormat24Hour()}
|
||||
@@ -170,7 +158,19 @@ public class TextClock extends AppCompatTextView {
|
||||
|
||||
public CharSequence getFormat() {
|
||||
return mFormat;
|
||||
}
|
||||
} private final ContentObserver mFormatChangeObserver = new ContentObserver(new Handler()) {
|
||||
@Override
|
||||
public void onChange(boolean selfChange) {
|
||||
chooseFormat();
|
||||
onTimeChanged();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onChange(boolean selfChange, Uri uri) {
|
||||
chooseFormat();
|
||||
onTimeChanged();
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Selects either one of {@link #getFormat12Hour()} or {@link #getFormat24Hour()}
|
||||
|
||||
@@ -0,0 +1,38 @@
|
||||
<?xml version="1.0" encoding="utf-8"?><!--
|
||||
~ Copyright 2022 Tarsin Norbin
|
||||
~
|
||||
~ This file is part of EhViewer
|
||||
~
|
||||
~ EhViewer is free software: you can redistribute it and/or modify it
|
||||
~ under the terms of the GNU GeneralPublic License as published
|
||||
~ by the Free Software Foundation,either version 3 of the License, or
|
||||
~ (at your option) any later version.
|
||||
~
|
||||
~ EhViewer 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 EhViewer.
|
||||
~ If not, see <https://www.gnu.org/licenses/>.
|
||||
-->
|
||||
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="44dp"
|
||||
android:height="44dp"
|
||||
android:viewportWidth="108"
|
||||
android:viewportHeight="108">
|
||||
<group
|
||||
android:scaleX="0.37947997"
|
||||
android:scaleY="0.37947997"
|
||||
android:translateX="35.1"
|
||||
android:translateY="39.584126">
|
||||
<path
|
||||
android:fillColor="@android:color/white"
|
||||
android:fillType="evenOdd"
|
||||
android:pathData="M39.893,68.066L39.893,75.977L0,75.977L0,4.59L39.893,4.59L39.893,12.5L8.984,12.5L8.984,34.766L38.086,34.766L38.086,42.578L8.984,42.578L8.984,68.066L39.893,68.066Z" />
|
||||
<path
|
||||
android:fillColor="@android:color/white"
|
||||
android:fillType="evenOdd"
|
||||
android:pathData="M99.609,75.977L90.918,75.977L90.918,41.699A23.436,23.436 0,0 0,90.662 38.109Q90.055,34.207 88.013,31.958Q85.629,29.334 81.028,28.863A20.84,20.84 0,0 0,78.906 28.76A23.134,23.134 0,0 0,74.45 29.16Q71.926,29.656 69.994,30.767A11.122,11.122 0,0 0,66.968 33.301A13.32,13.32 0,0 0,64.756 37.276Q63.399,40.971 63.213,46.495A53.517,53.517 0,0 0,63.184 48.291L63.184,75.977L54.395,75.977L54.395,0L63.184,0L63.184,22.266A66.935,66.935 0,0 1,63.115 25.383Q63.043,26.914 62.897,28.251A33.547,33.547 0,0 1,62.695 29.785L63.281,29.785A16.11,16.11 0,0 1,69.394 24.035A19.448,19.448 0,0 1,70.068 23.682A20.88,20.88 0,0 1,77.292 21.622A25.763,25.763 0,0 1,79.98 21.484A32.643,32.643 0,0 1,85.483 21.917Q91.249,22.905 94.678,26.147Q98.472,29.735 99.347,36.631A35.274,35.274 0,0 1,99.609 41.064L99.609,75.977Z" />
|
||||
</group>
|
||||
</vector>
|
||||
@@ -84,10 +84,10 @@
|
||||
<LinearLayout
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:paddingTop="8dp"
|
||||
android:paddingBottom="8dp"
|
||||
android:divider="@drawable/spacer_keyline"
|
||||
android:orientation="horizontal"
|
||||
android:paddingTop="8dp"
|
||||
android:paddingBottom="8dp"
|
||||
android:showDividers="middle">
|
||||
|
||||
<FrameLayout
|
||||
|
||||
@@ -230,8 +230,8 @@
|
||||
android:clickable="true"
|
||||
android:focusable="true"
|
||||
android:insetLeft="40dp"
|
||||
android:insetRight="40dp"
|
||||
android:insetTop="16dp"
|
||||
android:insetRight="40dp"
|
||||
android:text="@string/read">
|
||||
|
||||
<requestFocus />
|
||||
@@ -244,11 +244,11 @@
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1"
|
||||
android:clickable="true"
|
||||
android:nextFocusDown="@+id/torrent"
|
||||
android:focusable="true"
|
||||
android:insetLeft="40dp"
|
||||
android:insetTop="16dp"
|
||||
android:insetRight="40dp" />
|
||||
android:insetRight="40dp"
|
||||
android:nextFocusDown="@+id/torrent" />
|
||||
|
||||
|
||||
<android.widget.Space
|
||||
|
||||
@@ -188,11 +188,11 @@
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginEnd="@dimen/keyline_margin"
|
||||
app:chipSpacingHorizontal="8dp"
|
||||
android:ellipsize="end"
|
||||
android:singleLine="true"
|
||||
android:textAllCaps="true"
|
||||
app:chipIcon="@drawable/ic_baseline_label_24"
|
||||
app:chipSpacingHorizontal="8dp"
|
||||
app:ensureMinTouchTargetSize="true"
|
||||
app:layout_constraintBottom_toTopOf="@id/uploader"
|
||||
app:layout_constraintEnd_toEndOf="parent" />
|
||||
|
||||
@@ -18,4 +18,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_monochrome" />
|
||||
</adaptive-icon>
|
||||
@@ -18,4 +18,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_monochrome" />
|
||||
</adaptive-icon>
|
||||
@@ -1,21 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?><!--
|
||||
~ Copyright 2016 Hippo Seven
|
||||
~
|
||||
~ Licensed under the Apache License, Version 2.0 (the "License");
|
||||
~ you may not use this file except in compliance with the License.
|
||||
~ You may obtain a copy of the License at
|
||||
~
|
||||
~ http://www.apache.org/licenses/LICENSE-2.0
|
||||
~
|
||||
~ Unless required by applicable law or agreed to in writing, software
|
||||
~ distributed under the License is distributed on an "AS IS" BASIS,
|
||||
~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
~ See the License for the specific language governing permissions and
|
||||
~ limitations under the License.
|
||||
-->
|
||||
|
||||
<resources>
|
||||
|
||||
<!-- Custom preference -->
|
||||
|
||||
</resources>
|
||||
@@ -1,21 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?><!--
|
||||
~ Copyright 2016 Hippo Seven
|
||||
~
|
||||
~ Licensed under the Apache License, Version 2.0 (the "License");
|
||||
~ you may not use this file except in compliance with the License.
|
||||
~ You may obtain a copy of the License at
|
||||
~
|
||||
~ http://www.apache.org/licenses/LICENSE-2.0
|
||||
~
|
||||
~ Unless required by applicable law or agreed to in writing, software
|
||||
~ distributed under the License is distributed on an "AS IS" BASIS,
|
||||
~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
~ See the License for the specific language governing permissions and
|
||||
~ limitations under the License.
|
||||
-->
|
||||
|
||||
<resources>
|
||||
|
||||
<!-- Custom preference -->
|
||||
|
||||
</resources>
|
||||
@@ -1,19 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?><!--
|
||||
~ Copyright 2016 Hippo Seven
|
||||
~
|
||||
~ Licensed under the Apache License, Version 2.0 (the "License");
|
||||
~ you may not use this file except in compliance with the License.
|
||||
~ You may obtain a copy of the License at
|
||||
~
|
||||
~ http://www.apache.org/licenses/LICENSE-2.0
|
||||
~
|
||||
~ Unless required by applicable law or agreed to in writing, software
|
||||
~ distributed under the License is distributed on an "AS IS" BASIS,
|
||||
~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
~ See the License for the specific language governing permissions and
|
||||
~ limitations under the License.
|
||||
-->
|
||||
|
||||
<resources>
|
||||
|
||||
</resources>
|
||||
@@ -1,21 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?><!--
|
||||
~ Copyright 2016 Hippo Seven
|
||||
~
|
||||
~ Licensed under the Apache License, Version 2.0 (the "License");
|
||||
~ you may not use this file except in compliance with the License.
|
||||
~ You may obtain a copy of the License at
|
||||
~
|
||||
~ http://www.apache.org/licenses/LICENSE-2.0
|
||||
~
|
||||
~ Unless required by applicable law or agreed to in writing, software
|
||||
~ distributed under the License is distributed on an "AS IS" BASIS,
|
||||
~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
~ See the License for the specific language governing permissions and
|
||||
~ limitations under the License.
|
||||
-->
|
||||
|
||||
<resources>
|
||||
|
||||
<!-- Custom preference -->
|
||||
|
||||
</resources>
|
||||
@@ -1,20 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?><!--
|
||||
~ Copyright 2016 Hippo Seven
|
||||
~
|
||||
~ Licensed under the Apache License, Version 2.0 (the "License");
|
||||
~ you may not use this file except in compliance with the License.
|
||||
~ You may obtain a copy of the License at
|
||||
~
|
||||
~ http://www.apache.org/licenses/LICENSE-2.0
|
||||
~
|
||||
~ Unless required by applicable law or agreed to in writing, software
|
||||
~ distributed under the License is distributed on an "AS IS" BASIS,
|
||||
~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
~ See the License for the specific language governing permissions and
|
||||
~ limitations under the License.
|
||||
-->
|
||||
|
||||
<resources>
|
||||
|
||||
|
||||
</resources>
|
||||
File renamed without changes.
@@ -0,0 +1,55 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||
|
||||
<svg xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:cc="http://creativecommons.org/ns#" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:svg="http://www.w3.org/2000/svg" xmlns="http://www.w3.org/2000/svg" xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" width="646" height="250" id="svg8502" version="1.1" inkscape:version="0.91 r13725" sodipodi:docname="get-it-on-github.svg" inkscape:export-filename="/home/nixdorf/Lokaler Speicher/Build/andOTP/assets/badges/get-it-on-github.png" inkscape:export-xdpi="90" inkscape:export-ydpi="90">
|
||||
<defs id="defs8504" />
|
||||
<sodipodi:namedview id="base" pagecolor="#ffffff" bordercolor="#666666" borderopacity="1.0" inkscape:pageopacity="0.0" inkscape:pageshadow="2" inkscape:zoom="0.50000001" inkscape:cx="-223.13537" inkscape:cy="546.37524" inkscape:document-units="px" inkscape:current-layer="layer1" showgrid="true" fit-margin-top="0" fit-margin-left="0" fit-margin-right="0" fit-margin-bottom="0" inkscape:window-width="1920" inkscape:window-height="1021" inkscape:window-x="0" inkscape:window-y="31" inkscape:window-maximized="1" />
|
||||
<metadata id="metadata8507">
|
||||
<rdf:RDF>
|
||||
<cc:Work rdf:about="">
|
||||
<dc:format>image/svg+xml</dc:format>
|
||||
<dc:type rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||
<dc:title />
|
||||
<dc:creator>
|
||||
<cc:Agent>
|
||||
<dc:title>Andrew Nayenko</dc:title>
|
||||
</cc:Agent>
|
||||
</dc:creator>
|
||||
<dc:publisher>
|
||||
<cc:Agent>
|
||||
<dc:title>https://f-droid.org</dc:title>
|
||||
</cc:Agent>
|
||||
</dc:publisher>
|
||||
<cc:license rdf:resource="http://creativecommons.org/licenses/by-sa/3.0/" />
|
||||
<dc:contributor>
|
||||
<cc:Agent>
|
||||
<dc:title />
|
||||
</cc:Agent>
|
||||
</dc:contributor>
|
||||
</cc:Work>
|
||||
<cc:License rdf:about="http://creativecommons.org/licenses/by-sa/3.0/">
|
||||
<cc:permits rdf:resource="http://creativecommons.org/ns#Reproduction" />
|
||||
<cc:permits rdf:resource="http://creativecommons.org/ns#Distribution" />
|
||||
<cc:requires rdf:resource="http://creativecommons.org/ns#Notice" />
|
||||
<cc:requires rdf:resource="http://creativecommons.org/ns#Attribution" />
|
||||
<cc:permits rdf:resource="http://creativecommons.org/ns#DerivativeWorks" />
|
||||
<cc:requires rdf:resource="http://creativecommons.org/ns#ShareAlike" />
|
||||
</cc:License>
|
||||
</rdf:RDF>
|
||||
</metadata>
|
||||
<g inkscape:label="Layer 1" inkscape:groupmode="layer" id="layer1" transform="translate(-289,-312.36218)">
|
||||
<rect style="color:#000000;display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:#a6a6a6;stroke-width:4;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;marker:none;enable-background:accumulate" id="rect3007" width="560" height="164" x="332" y="355.36218" rx="20" ry="20" />
|
||||
<text sodipodi:linespacing="100%" id="text3013" y="402.36697" x="508.95129" style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:12.39519119px;line-height:100%;font-family:'DejaVu Sans';-inkscape-font-specification:'DejaVu Sans';letter-spacing:0px;word-spacing:0px;display:inline;overflow:visible;visibility:visible;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;marker:none;enable-background:accumulate" xml:space="preserve"><tspan y="402.36697" x="508.95129" id="tspan3015" sodipodi:role="line" style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:34.125px;font-family:'DejaVu Sans';-inkscape-font-specification:'DejaVu Sans'">GET IT ON</tspan></text>
|
||||
<text xml:space="preserve" style="color:black;font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:29.70882034px;line-height:100%;font-family:Rokkitt;-inkscape-font-specification:'Rokkitt Bold';text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;display:inline;overflow:visible;visibility:visible;fill:white;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;marker:none;enable-background:accumulate" x="508.21259" y="489.36108" id="text5902" sodipodi:linespacing="100%"><tspan sodipodi:role="line" id="tspan5904" x="508.21259" y="489.36108" style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:87.5px;line-height:100%;font-family:'Roboto Slab';-inkscape-font-specification:'Roboto Slab Bold';text-align:start;writing-mode:lr-tb;text-anchor:start;fill:white;fill-opacity:1">GitHub</tspan></text>
|
||||
<g transform="matrix(1.0017681,0,0,1.0017681,68.770756,92.660249)" id="g5136">
|
||||
<path style="fill:white;fill-opacity:1;fill-rule:evenodd;stroke:none" d="m 350.60937,282.4375 c -33.34765,0 -60.38671,27.03516 -60.38671,60.38672 0,26.67969 17.30078,49.3164 41.29687,57.30078 3.01563,0.55859 4.125,-1.30859 4.125,-2.90625 0,-1.4375 -0.0547,-6.19531 -0.082,-11.24219 -16.80078,3.65235 -20.34375,-7.125 -20.34375,-7.125 -2.75,-6.98047 -6.70703,-8.83594 -6.70703,-8.83594 -5.48047,-3.74609 0.41406,-3.67187 0.41406,-3.67187 6.0625,0.42578 9.25781,6.22266 9.25781,6.22266 5.38282,9.23437 14.125,6.5664 17.57032,5.02343 0.54296,-3.90234 2.10937,-6.57031 3.83593,-8.07812 -13.41406,-1.52735 -27.51562,-6.70313 -27.51562,-29.84375 0,-6.59375 2.35937,-11.98047 6.22265,-16.20703 -0.625,-1.52344 -2.6914,-7.66407 0.58594,-15.98047 0,0 5.07031,-1.625 16.60938,6.1875 4.82031,-1.33594 9.98437,-2.00781 15.11718,-2.03125 5.13282,0.0234 10.30079,0.69531 15.12891,2.03125 11.52344,-7.8125 16.58984,-6.1875 16.58984,-6.1875 3.28516,8.3164 1.21875,14.45703 0.58985,15.98047 3.87109,4.22656 6.21484,9.61328 6.21484,16.20703 0,23.19531 -14.125,28.30078 -27.57422,29.79687 2.16797,1.875 4.09766,5.55078 4.09766,11.1836 0,8.07812 -0.0703,14.58203 -0.0703,16.57031 0,1.60937 1.08593,3.49219 4.14843,2.89844 23.98047,-7.9961 41.26172,-30.6211 41.26172,-57.29297 0,-33.35156 -27.03515,-60.38672 -60.38672,-60.38672" id="path4937" inkscape:connector-curvature="0" />
|
||||
<path style="fill:white;fill-opacity:1;fill-rule:nonzero;stroke:none" d="m 313.09375,369.14062 c -0.13281,0.30079 -0.60547,0.38672 -1.03516,0.1836 -0.4375,-0.19922 -0.68359,-0.60547 -0.54297,-0.91016 0.12891,-0.30859 0.60157,-0.39062 1.03907,-0.1875 0.4414,0.19922 0.6914,0.61328 0.53906,0.91406" id="path4939" inkscape:connector-curvature="0" />
|
||||
<path style="fill:white;fill-opacity:1;fill-rule:nonzero;stroke:none" d="m 315.53906,371.86719 c -0.28906,0.26562 -0.85156,0.14453 -1.23437,-0.27735 -0.39453,-0.42187 -0.46875,-0.98437 -0.17578,-1.25781 0.29687,-0.26562 0.84375,-0.14062 1.23828,0.28125 0.39453,0.42578 0.47265,0.98438 0.17187,1.25391" id="path4941" inkscape:connector-curvature="0" />
|
||||
<path style="fill:white;fill-opacity:1;fill-rule:nonzero;stroke:none" d="m 317.92187,375.34375 c -0.37109,0.25781 -0.97656,0.0156 -1.35156,-0.51953 -0.37109,-0.53906 -0.37109,-1.17969 0.008,-1.4375 0.375,-0.25781 0.97266,-0.0274 1.35157,0.5039 0.36718,0.54688 0.36718,1.19141 -0.008,1.45313" id="path4943" inkscape:connector-curvature="0" />
|
||||
<path style="fill:white;fill-opacity:1;fill-rule:nonzero;stroke:none" d="m 321.18359,378.70312 c -0.33203,0.36719 -1.03906,0.26954 -1.55468,-0.23046 -0.52735,-0.48438 -0.67579,-1.17579 -0.34375,-1.54297 0.33593,-0.36328 1.04687,-0.26172 1.5664,0.23047 0.52344,0.48828 0.6836,1.18359 0.33203,1.54296" id="path4945-3" inkscape:connector-curvature="0" />
|
||||
<path style="fill:white;fill-opacity:1;fill-rule:nonzero;stroke:none" d="m 325.68359,380.65625 c -0.14843,0.47266 -0.82812,0.6875 -1.51172,0.48828 -0.68359,-0.20703 -1.1289,-0.76172 -0.99218,-1.24219 0.14453,-0.47265 0.82422,-0.69922 1.51562,-0.48437 0.67969,0.20703 1.12891,0.75781 0.98828,1.23828" id="path4947-6" inkscape:connector-curvature="0" />
|
||||
<path style="fill:white;fill-opacity:1;fill-rule:nonzero;stroke:none" d="m 330.625,381.01953 c 0.0156,0.49609 -0.5625,0.91016 -1.28125,0.91797 -0.72266,0.0156 -1.30859,-0.38672 -1.31641,-0.875 0,-0.50391 0.57032,-0.91406 1.28907,-0.92578 0.71875,-0.0156 1.30859,0.38672 1.30859,0.88281" id="path4949" inkscape:connector-curvature="0" />
|
||||
<path style="fill:white;fill-opacity:1;fill-rule:nonzero;stroke:none" d="m 335.22266,380.23437 c 0.0859,0.48829 -0.41407,0.98438 -1.125,1.11719 -0.70313,0.12891 -1.35157,-0.17187 -1.44141,-0.65234 -0.0859,-0.5 0.42187,-0.9961 1.12109,-1.125 0.71485,-0.125 1.35547,0.16797 1.44532,0.66015" id="path4951-7" inkscape:connector-curvature="0" />
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 8.5 KiB |
@@ -21,7 +21,7 @@ import android.graphics.Bitmap;
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
import java.io.FileDescriptor;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
import java.util.ArrayList;
|
||||
|
||||
/**
|
||||
* The {@code Image} is a image which stored pixel data in native heap
|
||||
@@ -31,20 +31,33 @@ public final class Image {
|
||||
|
||||
public static final int FORMAT_ANIMATED = 1;
|
||||
|
||||
private static final AtomicInteger sImageCount = new AtomicInteger();
|
||||
private static final ArrayList<Image> imageList = new ArrayList<>();
|
||||
private static boolean needEvictAll = false;
|
||||
|
||||
private final int mFormat;
|
||||
private final int mWidth;
|
||||
private final int mHeight;
|
||||
private long mNativePtr;
|
||||
private Throwable mRecycleTracker;
|
||||
|
||||
private Image(long nativePtr, int format, int width, int height) {
|
||||
if (needEvictAll)
|
||||
evictAll();
|
||||
|
||||
mNativePtr = nativePtr;
|
||||
mFormat = format;
|
||||
mWidth = width;
|
||||
mHeight = height;
|
||||
|
||||
sImageCount.getAndIncrement();
|
||||
imageList.add(this);
|
||||
}
|
||||
|
||||
public static void lazyEvictAll() {
|
||||
needEvictAll = true;
|
||||
}
|
||||
|
||||
private static void evictAll() {
|
||||
(new ArrayList<>(imageList)).forEach(Image::recycle);
|
||||
needEvictAll = false;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -84,7 +97,7 @@ public final class Image {
|
||||
* It is useful for debug.
|
||||
*/
|
||||
public static int getImageCount() {
|
||||
return sImageCount.get();
|
||||
return imageList.size();
|
||||
}
|
||||
|
||||
private static native Image nativeDecode(FileDescriptor fd);
|
||||
@@ -132,11 +145,7 @@ public final class Image {
|
||||
|
||||
private void checkRecycled() {
|
||||
if (mNativePtr == 0) {
|
||||
if (mRecycleTracker != null) {
|
||||
throw new IllegalStateException("The image is recycled.", mRecycleTracker);
|
||||
} else {
|
||||
throw new IllegalStateException("The image is recycled.");
|
||||
}
|
||||
throw new IllegalStateException("The image is recycled.");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -189,14 +198,11 @@ public final class Image {
|
||||
* It must be called when the image will not be used.
|
||||
* The image can't be used after this method is called.
|
||||
*/
|
||||
public void recycle() {
|
||||
public synchronized void recycle() {
|
||||
if (mNativePtr != 0) {
|
||||
nativeRecycle(mNativePtr);
|
||||
mNativePtr = 0;
|
||||
|
||||
sImageCount.getAndDecrement();
|
||||
|
||||
mRecycleTracker = new Throwable("It's a ImageRecycleTracker");
|
||||
imageList.remove(this);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -43,7 +43,7 @@ static char *passwd = NULL;
|
||||
static void *archiveAddr = NULL;
|
||||
static jlong archiveSize = 0;
|
||||
|
||||
const char supportExt[9][6] = {
|
||||
const char supportExt[9][6] = {
|
||||
"jpeg",
|
||||
"jpg",
|
||||
"png",
|
||||
@@ -60,7 +60,7 @@ static int filename_is_playable_file(const char *name) {
|
||||
if (!dotptr++)
|
||||
return false;
|
||||
int i;
|
||||
for (i=0; i<9; i++)
|
||||
for (i = 0; i < 9; i++)
|
||||
if (strcmp(dotptr, supportExt[i]) == 0)
|
||||
return true;
|
||||
return false;
|
||||
@@ -117,7 +117,6 @@ Java_com_hippo_UriArchiveAccessor_openArchive(JNIEnv *_, jobject thiz, jlong add
|
||||
need_encrypt = true;
|
||||
break;
|
||||
case 0: // format supports but no encrypted entry found
|
||||
case ARCHIVE_READ_FORMAT_ENCRYPTION_DONT_KNOW: // Sometimes we might not read through whole file|vm, but it means so far we haven't meet any encrypted entry yet
|
||||
default:
|
||||
need_encrypt = false;
|
||||
}
|
||||
@@ -128,7 +127,7 @@ Java_com_hippo_UriArchiveAccessor_openArchive(JNIEnv *_, jobject thiz, jlong add
|
||||
}
|
||||
|
||||
typedef struct Memarea {
|
||||
void* buffer;
|
||||
void *buffer;
|
||||
long size;
|
||||
} Memarea;
|
||||
|
||||
@@ -140,20 +139,18 @@ Java_com_hippo_UriArchiveAccessor_extracttoOutputStream(JNIEnv *_, jobject thiz,
|
||||
archive_alloc();
|
||||
cur_index = 0;
|
||||
}
|
||||
Memarea* memarea = malloc(sizeof(Memarea));
|
||||
Memarea *memarea = malloc(sizeof(Memarea));
|
||||
while (archive_read_next_header(arc, &entry) == ARCHIVE_OK) {
|
||||
if (!filename_is_playable_file(archive_entry_pathname(entry)))
|
||||
continue;
|
||||
if (cur_index++ == index) {
|
||||
memarea->size = archive_entry_size(entry);
|
||||
memarea->buffer = malloc(memarea->size);
|
||||
for (;;) {
|
||||
ret = archive_read_data(arc, memarea->buffer, memarea->size);
|
||||
if (ret < 0) {
|
||||
LOGE("%s%s", "Archive read failed:", archive_error_string(arc));
|
||||
}
|
||||
break;
|
||||
}
|
||||
ret = archive_read_data(arc, memarea->buffer, memarea->size);
|
||||
if (ret != memarea->size)
|
||||
LOGE("%s", "No enough data read, WTF?");
|
||||
if (ret < 0)
|
||||
LOGE("%s%s", "Archive read failed:", archive_error_string(arc));
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -180,7 +177,6 @@ Java_com_hippo_UriArchiveAccessor_providePassword(JNIEnv *_, jobject thiz, jstri
|
||||
free(passwd);
|
||||
passwd = calloc(len, sizeof(char));
|
||||
strcpy(passwd, (*env)->GetStringUTFChars(env, str, NULL));
|
||||
LOGI("%s%s", "Passwd is ", passwd);
|
||||
archive_alloc();
|
||||
while (archive_read_next_header(arc, &entry) == ARCHIVE_OK) {
|
||||
if (!filename_is_playable_file(archive_entry_pathname(entry)))
|
||||
|
||||
@@ -1,17 +1,20 @@
|
||||
/*
|
||||
* Copyright 2015 Hippo Seven
|
||||
* Copyright 2022 Tarsin Norbin
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
* This file is part of EhViewer
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* EhViewer 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.
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
* EhViewer 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
|
||||
* EhViewer. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <android/data_space.h>
|
||||
@@ -33,12 +36,14 @@ void decodeCommon(IMAGE *image, SOURCE *src) {
|
||||
image->alpha =
|
||||
AImageDecoderHeaderInfo_getAlphaFlags(headerInfo) == ANDROID_BITMAP_FLAGS_ALPHA_PREMUL;
|
||||
src->stride = AImageDecoder_getMinimumStride(decoder);
|
||||
image->bufferLen = image->height * src->stride;
|
||||
image->bufferLen = (int) (image->height * src->stride);
|
||||
image->buffer = malloc(image->bufferLen);
|
||||
if (image->isAnimated) {
|
||||
AImageDecoder_setInternallyHandleDisposePrevious(decoder, false);
|
||||
src->frameInfo = AImageDecoderFrameInfo_create();
|
||||
AImageDecoder_getFrameInfo(decoder, src->frameInfo);
|
||||
AImageDecoderFrameInfo *frameInfo = AImageDecoderFrameInfo_create();
|
||||
AImageDecoder_getFrameInfo(decoder, frameInfo);
|
||||
image->delay = (int) AImageDecoderFrameInfo_getDuration(frameInfo) / 1000000;
|
||||
AImageDecoderFrameInfo_delete(frameInfo);
|
||||
}
|
||||
AImageDecoder_decodeImage(decoder, image->buffer, src->stride, image->bufferLen);
|
||||
if (!image->isAnimated) {
|
||||
@@ -47,9 +52,10 @@ void decodeCommon(IMAGE *image, SOURCE *src) {
|
||||
}
|
||||
}
|
||||
|
||||
IMAGE *createFromFd(JNIEnv *env, int fd) {
|
||||
AImageDecoder *decoder;
|
||||
AImageDecoder_createFromFd(fd, &decoder);
|
||||
IMAGE *createFromFd(int fd) {
|
||||
AImageDecoder *decoder = NULL;
|
||||
if (AImageDecoder_createFromFd(fd, &decoder) != ANDROID_IMAGE_DECODER_SUCCESS)
|
||||
return NULL;
|
||||
IMAGE *image = calloc(1, sizeof(IMAGE));
|
||||
SOURCE *src = calloc(1, sizeof(SOURCE));
|
||||
src->decoder = decoder;
|
||||
@@ -58,7 +64,7 @@ IMAGE *createFromFd(JNIEnv *env, int fd) {
|
||||
return image;
|
||||
}
|
||||
|
||||
IMAGE *createFromAddr(JNIEnv *env, void *addr, long size) {
|
||||
IMAGE *createFromAddr(void *addr, long size) {
|
||||
AImageDecoder *decoder;
|
||||
AImageDecoder_createFromBuffer((const void *) addr, size, &decoder);
|
||||
IMAGE *image = calloc(1, sizeof(IMAGE));
|
||||
@@ -80,7 +86,7 @@ IMAGE *create(int32_t width, int32_t height, const void *data) {
|
||||
plain->width = width;
|
||||
plain->height = height;
|
||||
plain->buffer = buffer;
|
||||
plain->bufferLen = length;
|
||||
plain->bufferLen = (int) length;
|
||||
|
||||
return plain;
|
||||
}
|
||||
@@ -103,9 +109,3 @@ void advance(IMAGE *image) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int get_delay(IMAGE *image) {
|
||||
if (image->isAnimated)
|
||||
return (int) AImageDecoderFrameInfo_getDuration(image->src->frameInfo) / 1000000;
|
||||
return 0;
|
||||
}
|
||||
@@ -1,17 +1,20 @@
|
||||
/*
|
||||
* Copyright 2015 Hippo Seven
|
||||
* Copyright 2022 Tarsin Norbin
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
* This file is part of EhViewer
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* EhViewer 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.
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
* EhViewer 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
|
||||
* EhViewer. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef IMAGE_IMAGE_H
|
||||
@@ -19,15 +22,11 @@
|
||||
|
||||
#include <android/imagedecoder.h>
|
||||
#include <stdbool.h>
|
||||
#include <jni.h>
|
||||
|
||||
#include "log.h"
|
||||
|
||||
typedef struct {
|
||||
AImageDecoder *decoder;
|
||||
void *srcBuffer;
|
||||
size_t stride;
|
||||
AImageDecoderFrameInfo *frameInfo;
|
||||
int fd;
|
||||
} SOURCE;
|
||||
|
||||
@@ -38,13 +37,13 @@ typedef struct {
|
||||
int bufferLen;
|
||||
bool isAnimated;
|
||||
bool alpha;
|
||||
int delay;
|
||||
SOURCE *src;
|
||||
} IMAGE;
|
||||
|
||||
static void recycleSource(SOURCE *src) {
|
||||
if (!src)
|
||||
return;
|
||||
AImageDecoderFrameInfo_delete(src->frameInfo);
|
||||
AImageDecoder_delete(src->decoder);
|
||||
free(src->srcBuffer);
|
||||
free(src);
|
||||
@@ -58,9 +57,9 @@ static void recycle(IMAGE *image) {
|
||||
free(image);
|
||||
}
|
||||
|
||||
IMAGE *createFromFd(JNIEnv *env, int fd);
|
||||
IMAGE *createFromFd(int fd);
|
||||
|
||||
IMAGE *createFromAddr(JNIEnv *env, void *addr, long size);
|
||||
IMAGE *createFromAddr(void *addr, long size);
|
||||
|
||||
IMAGE *create(int32_t width, int32_t height, const void *data);
|
||||
|
||||
@@ -70,6 +69,4 @@ void render(IMAGE *image, int src_x, int src_y,
|
||||
|
||||
void advance(IMAGE *image);
|
||||
|
||||
int get_delay(IMAGE *image);
|
||||
|
||||
#endif //IMAGE_IMAGE_H
|
||||
#endif /* IMAGE_IMAGE_H */
|
||||
@@ -26,10 +26,4 @@ bool copy_pixels(const void *src, int src_w, int src_h, int src_x, int src_y,
|
||||
void *dst, int dst_w, int dst_h, int dst_x, int dst_y,
|
||||
int width, int height);
|
||||
|
||||
#define STRINGIZE(L) #L
|
||||
#define MAKESTRING(M, L) M(L)
|
||||
|
||||
#define MIN(a, b) (((a) < (b)) ? (a) : (b))
|
||||
#define MAX(a, b) (((a) > (b)) ? (a) : (b))
|
||||
|
||||
#endif //IMAGE_IMAGE_UTILS_H
|
||||
#endif /* IMAGE_IMAGE_UTILS_H */
|
||||
@@ -17,15 +17,13 @@
|
||||
#include <stdlib.h>
|
||||
#include <android/bitmap.h>
|
||||
#include <GLES2/gl2.h>
|
||||
#include <jni.h>
|
||||
|
||||
#include "java_wrapper.h"
|
||||
#include "image.h"
|
||||
#include "image_utils.h"
|
||||
#include "log.h"
|
||||
|
||||
static JavaVM *jvm;
|
||||
|
||||
static void *tile_buffer;
|
||||
static void *tile_buffer = NULL;
|
||||
|
||||
static int jniGetFDFromFileDescriptor(JNIEnv *env, jobject fileDescriptor) {
|
||||
jint fd = -1;
|
||||
@@ -41,54 +39,22 @@ static int jniGetFDFromFileDescriptor(JNIEnv *env, jobject fileDescriptor) {
|
||||
return fd;
|
||||
}
|
||||
|
||||
JNIEnv *obtain_env(bool *attach) {
|
||||
JNIEnv *env;
|
||||
switch ((*jvm)->GetEnv(jvm, (void **) &env, JNI_VERSION_1_6)) {
|
||||
case JNI_EDETACHED:
|
||||
if ((*jvm)->AttachCurrentThread(jvm, &env, NULL) == JNI_OK) {
|
||||
*attach = true;
|
||||
return env;
|
||||
} else {
|
||||
return NULL;
|
||||
}
|
||||
case JNI_OK:
|
||||
*attach = false;
|
||||
return env;
|
||||
default:
|
||||
case JNI_EVERSION:
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
void release_env() {
|
||||
(*jvm)->DetachCurrentThread(jvm);
|
||||
}
|
||||
|
||||
jobject create_image_object(JNIEnv *env, void *ptr, int format, int width, int height) {
|
||||
jclass image_clazz;
|
||||
jmethodID constructor;
|
||||
|
||||
image_clazz = (*env)->FindClass(env, "com/hippo/image/Image");
|
||||
constructor = (*env)->GetMethodID(env, image_clazz, "<init>", "(JIII)V");
|
||||
if (constructor == 0) {
|
||||
LOGE(MSG("Can't find Image object constructor"));
|
||||
return NULL;
|
||||
} else {
|
||||
return (*env)->NewObject(env, image_clazz, constructor,
|
||||
(jlong) (uintptr_t) ptr, (jint) format, (jint) width,
|
||||
(jint) height);
|
||||
}
|
||||
return (*env)->NewObject(env, image_clazz, constructor,
|
||||
(jlong) (uintptr_t) ptr, (jint) format, (jint) width,
|
||||
(jint) height);
|
||||
}
|
||||
|
||||
JNIEXPORT jobject JNICALL
|
||||
Java_com_hippo_image_Image_nativeDecodeFdInt(JNIEnv *env, jclass clazz, jint fd) {
|
||||
IMAGE *image;
|
||||
|
||||
image = createFromFd(env, fd);
|
||||
if (image == NULL) {
|
||||
IMAGE *image = createFromFd(fd);
|
||||
if (!image)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return create_image_object(env, image, image->isAnimated, image->width, image->height);
|
||||
}
|
||||
|
||||
@@ -106,10 +72,6 @@ Java_com_hippo_image_Image_nativeCreate(JNIEnv *env, jclass clazz, jobject bitma
|
||||
|
||||
AndroidBitmap_getInfo(env, bitmap, &info);
|
||||
AndroidBitmap_lockPixels(env, bitmap, &pixels);
|
||||
if (pixels == NULL) {
|
||||
LOGE(MSG("Can't lock bitmap pixels"));
|
||||
return NULL;
|
||||
}
|
||||
|
||||
image = create(info.width, info.height, pixels);
|
||||
AndroidBitmap_unlockPixels(env, bitmap);
|
||||
@@ -125,10 +87,6 @@ Java_com_hippo_image_Image_nativeRender(JNIEnv *env, jclass clazz, jlong ptr, ji
|
||||
|
||||
AndroidBitmap_getInfo(env, dst, &info);
|
||||
AndroidBitmap_lockPixels(env, dst, &pixels);
|
||||
if (pixels == NULL) {
|
||||
LOGE(MSG("Can't lock bitmap pixels"));
|
||||
return;
|
||||
}
|
||||
|
||||
render((IMAGE *) ptr, src_x, src_y, pixels, info.width, info.height, dst_x, dst_y, width,
|
||||
height);
|
||||
@@ -160,7 +118,7 @@ Java_com_hippo_image_Image_nativeAdvance(JNIEnv *env, jclass clazz, jlong ptr) {
|
||||
|
||||
JNIEXPORT jint JNICALL
|
||||
Java_com_hippo_image_Image_nativeGetDelay(JNIEnv *env, jclass clazz, jlong ptr) {
|
||||
return get_delay((IMAGE *) ptr);
|
||||
return ((IMAGE *) ptr)->delay;
|
||||
}
|
||||
|
||||
JNIEXPORT jboolean JNICALL
|
||||
@@ -173,14 +131,12 @@ Java_com_hippo_image_Image_nativeRecycle(JNIEnv *env, jclass clazz, jlong ptr) {
|
||||
recycle((IMAGE *) ptr);
|
||||
}
|
||||
|
||||
bool image_onLoad(JavaVM *vm) {
|
||||
jvm = vm;
|
||||
bool image_onLoad() {
|
||||
tile_buffer = malloc(IMAGE_TILE_MAX_SIZE * 4);
|
||||
return true;
|
||||
return tile_buffer != NULL;
|
||||
}
|
||||
|
||||
JNIEXPORT void JNICALL
|
||||
JNI_OnUnload(JavaVM *vm, void *reserved) {
|
||||
void image_onUnload() {
|
||||
free(tile_buffer);
|
||||
tile_buffer = NULL;
|
||||
}
|
||||
@@ -188,7 +144,7 @@ JNI_OnUnload(JavaVM *vm, void *reserved) {
|
||||
JNIEXPORT jobject JNICALL
|
||||
Java_com_hippo_image_Image_nativeDecodeAddr(JNIEnv *env, jclass clazz, jlong addr) {
|
||||
Memarea *memarea = (Memarea *) addr;
|
||||
IMAGE *image = createFromAddr(env, memarea->buffer, memarea->size);
|
||||
IMAGE *image = createFromAddr(memarea->buffer, memarea->size);
|
||||
free(memarea);
|
||||
return create_image_object(env, image, image->isAnimated, image->width, image->height);
|
||||
}
|
||||
@@ -20,7 +20,6 @@
|
||||
#ifndef IMAGE_JAVA_WRAPPER_H
|
||||
#define IMAGE_JAVA_WRAPPER_H
|
||||
|
||||
#include <jni.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#define IMAGE_TILE_MAX_SIZE (512 * 512)
|
||||
@@ -30,10 +29,8 @@ typedef struct Memarea {
|
||||
long size;
|
||||
} Memarea;
|
||||
|
||||
bool image_onLoad(JavaVM *vm);
|
||||
bool image_onLoad();
|
||||
|
||||
JNIEnv *obtain_env(bool *attach);
|
||||
void image_onUnload();
|
||||
|
||||
void release_env();
|
||||
|
||||
#endif // IMAGE_JAVA_WRAPPER_H
|
||||
#endif /* IMAGE_JAVA_WRAPPER_H */
|
||||
@@ -27,11 +27,4 @@
|
||||
#define LOGE(...) __android_log_print(ANDROID_LOG_ERROR, TAG ,__VA_ARGS__)
|
||||
#define LOGF(...) __android_log_print(ANDROID_LOG_FATAL, TAG ,__VA_ARGS__)
|
||||
|
||||
#define FILE_LINE MAKESTRING(STRINGIZE, __LINE__ )
|
||||
#define MSG(msg) __FILE__ "(" FILE_LINE "): "msg
|
||||
|
||||
#define OUT_OF_MEMORY "Out of memory"
|
||||
|
||||
#define WTF_OM LOGE(MSG(OUT_OF_MEMORY))
|
||||
|
||||
#endif //LOG_H
|
||||
#endif /* LOG_H */
|
||||
@@ -39,6 +39,11 @@ JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM *vm, void *reserved) {
|
||||
return JNI_VERSION_1_6;
|
||||
}
|
||||
|
||||
JNIEXPORT void JNICALL
|
||||
JNI_OnUnload(JavaVM *vm, void *reserved) {
|
||||
image_onUnload();
|
||||
}
|
||||
|
||||
JNIEXPORT jstring JNICALL
|
||||
Java_com_hippo_Native_getlibarchiveVersion(JNIEnv *env, jclass clazz) {
|
||||
return (*env)->NewStringUTF(env, ARCHIVE_VERSION_STRING);
|
||||
|
||||
@@ -1,4 +1,9 @@
|
||||
{
|
||||
"baseBranches": [
|
||||
"1.8.x.x",
|
||||
"1.7.x.x"
|
||||
],
|
||||
|
||||
"extends": [
|
||||
"config:base"
|
||||
]
|
||||
|
||||
Reference in new issue
Block a user