From 6111a96abd0e80d65a5e7c05f8f51e4cc3283964 Mon Sep 17 00:00:00 2001 From: VaishnaV Date: Thu, 7 Nov 2024 16:40:10 +0530 Subject: [PATCH] Faulty commit --- ...agmentStatePagerAdapterMenuWorkaround.java | 344 ------------- .../giga/io/ChunkFileInputStream.java | 155 ------ .../shandian/giga/io/CircularFileWriter.java | 486 ------------------ .../java/us/shandian/giga/io/FileStream.java | 131 ----- .../us/shandian/giga/io/FileStreamSAF.java | 150 ------ .../us/shandian/giga/io/ProgressReport.java | 11 - 6 files changed, 1277 deletions(-) delete mode 100644 app/src/main/java/androidx/fragment/app/FragmentStatePagerAdapterMenuWorkaround.java delete mode 100644 app/src/main/java/us/shandian/giga/io/ChunkFileInputStream.java delete mode 100644 app/src/main/java/us/shandian/giga/io/CircularFileWriter.java delete mode 100644 app/src/main/java/us/shandian/giga/io/FileStream.java delete mode 100644 app/src/main/java/us/shandian/giga/io/FileStreamSAF.java delete mode 100644 app/src/main/java/us/shandian/giga/io/ProgressReport.java diff --git a/app/src/main/java/androidx/fragment/app/FragmentStatePagerAdapterMenuWorkaround.java b/app/src/main/java/androidx/fragment/app/FragmentStatePagerAdapterMenuWorkaround.java deleted file mode 100644 index 8d03a148604..00000000000 --- a/app/src/main/java/androidx/fragment/app/FragmentStatePagerAdapterMenuWorkaround.java +++ /dev/null @@ -1,344 +0,0 @@ -/* - * Copyright 2018 The Android Open Source Project - * - * 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. - */ - -package androidx.fragment.app; - -import android.os.Bundle; -import android.os.Parcelable; -import android.util.Log; -import android.view.View; -import android.view.ViewGroup; - -import androidx.annotation.IntDef; -import androidx.annotation.NonNull; -import androidx.annotation.Nullable; -import androidx.core.os.BundleCompat; -import androidx.lifecycle.Lifecycle; -import androidx.viewpager.widget.PagerAdapter; - -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.util.ArrayList; - -// TODO: Replace this deprecated class with its ViewPager2 counterpart - -/** - * This is a copy from {@link androidx.fragment.app.FragmentStatePagerAdapter}. - *

- * It includes a workaround to fix the menu visibility when the adapter is restored. - *

- *

- * When restoring the state of this adapter, all the fragments' menu visibility were set to false, - * effectively disabling the menu from the user until he switched pages or another event - * that triggered the menu to be visible again happened. - *

- *

- * Check out the changes in: - *

- * - * - * @deprecated Switch to {@link androidx.viewpager2.widget.ViewPager2} and use - * {@link androidx.viewpager2.adapter.FragmentStateAdapter} instead. - */ -@SuppressWarnings("deprecation") -@Deprecated -public abstract class FragmentStatePagerAdapterMenuWorkaround extends PagerAdapter { - private static final String TAG = "FragmentStatePagerAdapt"; - private static final boolean DEBUG = false; - - @Retention(RetentionPolicy.SOURCE) - @IntDef({BEHAVIOR_SET_USER_VISIBLE_HINT, BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT}) - private @interface Behavior { } - - /** - * Indicates that {@link Fragment#setUserVisibleHint(boolean)} will be called when the current - * fragment changes. - * - * @deprecated This behavior relies on the deprecated - * {@link Fragment#setUserVisibleHint(boolean)} API. Use - * {@link #BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT} to switch to its replacement, - * {@link FragmentTransaction#setMaxLifecycle}. - * @see #FragmentStatePagerAdapterMenuWorkaround(FragmentManager, int) - */ - @Deprecated - public static final int BEHAVIOR_SET_USER_VISIBLE_HINT = 0; - - /** - * Indicates that only the current fragment will be in the {@link Lifecycle.State#RESUMED} - * state. All other Fragments are capped at {@link Lifecycle.State#STARTED}. - * - * @see #FragmentStatePagerAdapterMenuWorkaround(FragmentManager, int) - */ - public static final int BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT = 1; - - private final FragmentManager mFragmentManager; - private final int mBehavior; - private FragmentTransaction mCurTransaction = null; - - private final ArrayList mSavedState = new ArrayList<>(); - private final ArrayList mFragments = new ArrayList<>(); - private Fragment mCurrentPrimaryItem = null; - private boolean mExecutingFinishUpdate; - - /** - * Constructor for {@link FragmentStatePagerAdapterMenuWorkaround} - * that sets the fragment manager for the adapter. This is the equivalent of calling - * {@link #FragmentStatePagerAdapterMenuWorkaround(FragmentManager, int)} and passing in - * {@link #BEHAVIOR_SET_USER_VISIBLE_HINT}. - * - *

Fragments will have {@link Fragment#setUserVisibleHint(boolean)} called whenever the - * current Fragment changes.

- * - * @param fm fragment manager that will interact with this adapter - * @deprecated use {@link #FragmentStatePagerAdapterMenuWorkaround(FragmentManager, int)} with - * {@link #BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT} - */ - @Deprecated - public FragmentStatePagerAdapterMenuWorkaround(@NonNull final FragmentManager fm) { - this(fm, BEHAVIOR_SET_USER_VISIBLE_HINT); - } - - /** - * Constructor for {@link FragmentStatePagerAdapterMenuWorkaround}. - * - * If {@link #BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT} is passed in, then only the current - * Fragment is in the {@link Lifecycle.State#RESUMED} state, while all other fragments are - * capped at {@link Lifecycle.State#STARTED}. If {@link #BEHAVIOR_SET_USER_VISIBLE_HINT} is - * passed, all fragments are in the {@link Lifecycle.State#RESUMED} state and there will be - * callbacks to {@link Fragment#setUserVisibleHint(boolean)}. - * - * @param fm fragment manager that will interact with this adapter - * @param behavior determines if only current fragments are in a resumed state - */ - public FragmentStatePagerAdapterMenuWorkaround(@NonNull final FragmentManager fm, - @Behavior final int behavior) { - mFragmentManager = fm; - mBehavior = behavior; - } - - /** - * @param position the position of the item you want - * @return the {@link Fragment} associated with a specified position - */ - @NonNull - public abstract Fragment getItem(int position); - - @Override - public void startUpdate(@NonNull final ViewGroup container) { - if (container.getId() == View.NO_ID) { - throw new IllegalStateException("ViewPager with adapter " + this - + " requires a view id"); - } - } - - @SuppressWarnings("deprecation") - @NonNull - @Override - public Object instantiateItem(@NonNull final ViewGroup container, final int position) { - // If we already have this item instantiated, there is nothing - // to do. This can happen when we are restoring the entire pager - // from its saved state, where the fragment manager has already - // taken care of restoring the fragments we previously had instantiated. - if (mFragments.size() > position) { - final Fragment f = mFragments.get(position); - if (f != null) { - return f; - } - } - - if (mCurTransaction == null) { - mCurTransaction = mFragmentManager.beginTransaction(); - } - - final Fragment fragment = getItem(position); - if (DEBUG) { - Log.v(TAG, "Adding item #" + position + ": f=" + fragment); - } - if (mSavedState.size() > position) { - final Fragment.SavedState fss = mSavedState.get(position); - if (fss != null) { - fragment.setInitialSavedState(fss); - } - } - while (mFragments.size() <= position) { - mFragments.add(null); - } - fragment.setMenuVisibility(false); - if (mBehavior == BEHAVIOR_SET_USER_VISIBLE_HINT) { - fragment.setUserVisibleHint(false); - } - - mFragments.set(position, fragment); - mCurTransaction.add(container.getId(), fragment); - - if (mBehavior == BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT) { - mCurTransaction.setMaxLifecycle(fragment, Lifecycle.State.STARTED); - } - - return fragment; - } - - @Override - public void destroyItem(@NonNull final ViewGroup container, final int position, - @NonNull final Object object) { - final Fragment fragment = (Fragment) object; - - if (mCurTransaction == null) { - mCurTransaction = mFragmentManager.beginTransaction(); - } - if (DEBUG) { - Log.v(TAG, "Removing item #" + position + ": f=" + object - + " v=" + ((Fragment) object).getView()); - } - while (mSavedState.size() <= position) { - mSavedState.add(null); - } - mSavedState.set(position, fragment.isAdded() - ? mFragmentManager.saveFragmentInstanceState(fragment) : null); - mFragments.set(position, null); - - mCurTransaction.remove(fragment); - if (fragment.equals(mCurrentPrimaryItem)) { - mCurrentPrimaryItem = null; - } - } - - @Override - @SuppressWarnings({"ReferenceEquality", "deprecation"}) - public void setPrimaryItem(@NonNull final ViewGroup container, final int position, - @NonNull final Object object) { - final Fragment fragment = (Fragment) object; - if (fragment != mCurrentPrimaryItem) { - if (mCurrentPrimaryItem != null) { - mCurrentPrimaryItem.setMenuVisibility(false); - if (mBehavior == BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT) { - if (mCurTransaction == null) { - mCurTransaction = mFragmentManager.beginTransaction(); - } - mCurTransaction.setMaxLifecycle(mCurrentPrimaryItem, Lifecycle.State.STARTED); - } else { - mCurrentPrimaryItem.setUserVisibleHint(false); - } - } - fragment.setMenuVisibility(true); - if (mBehavior == BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT) { - if (mCurTransaction == null) { - mCurTransaction = mFragmentManager.beginTransaction(); - } - mCurTransaction.setMaxLifecycle(fragment, Lifecycle.State.RESUMED); - } else { - fragment.setUserVisibleHint(true); - } - - mCurrentPrimaryItem = fragment; - } - } - - @Override - public void finishUpdate(@NonNull final ViewGroup container) { - if (mCurTransaction != null) { - // We drop any transactions that attempt to be committed - // from a re-entrant call to finishUpdate(). We need to - // do this as a workaround for Robolectric running measure/layout - // calls inline rather than allowing them to be posted - // as they would on a real device. - if (!mExecutingFinishUpdate) { - try { - mExecutingFinishUpdate = true; - mCurTransaction.commitNowAllowingStateLoss(); - } finally { - mExecutingFinishUpdate = false; - } - } - mCurTransaction = null; - } - } - - @Override - public boolean isViewFromObject(@NonNull final View view, @NonNull final Object object) { - return ((Fragment) object).getView() == view; - } - - //!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! - private final String selectedFragment = "selected_fragment"; - //!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! - - @Override - @Nullable - public Parcelable saveState() { - Bundle state = null; - if (!mSavedState.isEmpty()) { - state = new Bundle(); - state.putParcelableArrayList("states", mSavedState); - } - for (int i = 0; i < mFragments.size(); i++) { - final Fragment f = mFragments.get(i); - if (f != null && f.isAdded()) { - if (state == null) { - state = new Bundle(); - } - final String key = "f" + i; - mFragmentManager.putFragment(state, key, f); - - //!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! - // Check if it's the same fragment instance - if (f == mCurrentPrimaryItem) { - state.putString(selectedFragment, key); - } - //!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! - } - } - return state; - } - - @Override - public void restoreState(@Nullable final Parcelable state, @Nullable final ClassLoader loader) { - if (state != null) { - final Bundle bundle = (Bundle) state; - bundle.setClassLoader(loader); - final var states = BundleCompat.getParcelableArrayList(bundle, "states", - Fragment.SavedState.class); - mSavedState.clear(); - mFragments.clear(); - if (states != null) { - mSavedState.addAll(states); - } - final Iterable keys = bundle.keySet(); - for (final String key : keys) { - if (key.startsWith("f")) { - final int index = Integer.parseInt(key.substring(1)); - final Fragment f = mFragmentManager.getFragment(bundle, key); - if (f != null) { - while (mFragments.size() <= index) { - mFragments.add(null); - } - //!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! - final boolean wasSelected = bundle.getString(selectedFragment, "") - .equals(key); - f.setMenuVisibility(wasSelected); - //!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! - mFragments.set(index, f); - } else { - Log.w(TAG, "Bad fragment at key " + key); - } - } - } - } - } -} diff --git a/app/src/main/java/us/shandian/giga/io/ChunkFileInputStream.java b/app/src/main/java/us/shandian/giga/io/ChunkFileInputStream.java deleted file mode 100644 index f7edf397574..00000000000 --- a/app/src/main/java/us/shandian/giga/io/ChunkFileInputStream.java +++ /dev/null @@ -1,155 +0,0 @@ -package us.shandian.giga.io; - -import org.schabi.newpipe.streams.io.SharpStream; - -import java.io.IOException; - -public class ChunkFileInputStream extends SharpStream { - private static final int REPORT_INTERVAL = 256 * 1024; - - private SharpStream source; - private final long offset; - private final long length; - private long position; - - private long progressReport; - private final ProgressReport onProgress; - - public ChunkFileInputStream(SharpStream target, long start, long end, ProgressReport callback) throws IOException { - source = target; - offset = start; - length = end - start; - position = 0; - onProgress = callback; - progressReport = REPORT_INTERVAL; - - if (length < 1) { - source.close(); - throw new IOException("The chunk is empty or invalid"); - } - if (source.length() < end) { - try { - throw new IOException(String.format("invalid file length. expected = %s found = %s", end, source.length())); - } finally { - source.close(); - } - } - - source.seek(offset); - } - - /** - * Get absolute position on file - * - * @return the position - */ - public long getFilePointer() { - return offset + position; - } - - @Override - public int read() throws IOException { - if ((position + 1) > length) { - return 0; - } - - int res = source.read(); - if (res >= 0) { - position++; - } - - return res; - } - - @Override - public int read(byte[] b) throws IOException { - return read(b, 0, b.length); - } - - @Override - public int read(byte[] b, int off, int len) throws IOException { - if ((position + len) > length) { - len = (int) (length - position); - } - if (len == 0) { - return 0; - } - - int res = source.read(b, off, len); - position += res; - - if (onProgress != null && position > progressReport) { - onProgress.report(position); - progressReport = position + REPORT_INTERVAL; - } - - return res; - } - - @Override - public long skip(long pos) throws IOException { - pos = Math.min(pos + position, length); - - if (pos == 0) { - return 0; - } - - source.seek(offset + pos); - - long oldPos = position; - position = pos; - - return pos - oldPos; - } - - @Override - public long available() { - return length - position; - } - - @SuppressWarnings("EmptyCatchBlock") - @Override - public void close() { - source.close(); - source = null; - } - - @Override - public boolean isClosed() { - return source == null; - } - - @Override - public void rewind() throws IOException { - position = 0; - source.seek(offset); - } - - @Override - public boolean canRewind() { - return true; - } - - @Override - public boolean canRead() { - return true; - } - - @Override - public boolean canWrite() { - return false; - } - - @Override - public void write(byte value) { - } - - @Override - public void write(byte[] buffer) { - } - - @Override - public void write(byte[] buffer, int offset, int count) { - } - -} diff --git a/app/src/main/java/us/shandian/giga/io/CircularFileWriter.java b/app/src/main/java/us/shandian/giga/io/CircularFileWriter.java deleted file mode 100644 index 4473fa7f953..00000000000 --- a/app/src/main/java/us/shandian/giga/io/CircularFileWriter.java +++ /dev/null @@ -1,486 +0,0 @@ -package us.shandian.giga.io; - -import androidx.annotation.NonNull; - -import org.schabi.newpipe.streams.io.SharpStream; - -import java.io.File; -import java.io.FileNotFoundException; -import java.io.IOException; -import java.util.Objects; - -public class CircularFileWriter extends SharpStream { - - private static final int QUEUE_BUFFER_SIZE = 8 * 1024;// 8 KiB - private static final int COPY_BUFFER_SIZE = 128 * 1024; // 128 KiB - private static final int NOTIFY_BYTES_INTERVAL = 64 * 1024;// 64 KiB - private static final int THRESHOLD_AUX_LENGTH = 15 * 1024 * 1024;// 15 MiB - - private final OffsetChecker callback; - - public ProgressReport onProgress; - public WriteErrorHandle onWriteError; - - private long reportPosition; - private long maxLengthKnown = -1; - - private BufferedFile out; - private BufferedFile aux; - - public CircularFileWriter(SharpStream target, File temp, OffsetChecker checker) throws IOException { - Objects.requireNonNull(checker); - - if (!temp.exists()) { - if (!temp.createNewFile()) { - throw new IOException("Cannot create a temporal file"); - } - } - - aux = new BufferedFile(temp); - out = new BufferedFile(target); - - callback = checker; - - reportPosition = NOTIFY_BYTES_INTERVAL; - } - - private void flushAuxiliar(long amount) throws IOException { - if (aux.length < 1) { - return; - } - - out.flush(); - aux.flush(); - - boolean underflow = aux.offset < aux.length || out.offset < out.length; - byte[] buffer = new byte[COPY_BUFFER_SIZE]; - - aux.target.seek(0); - out.target.seek(out.length); - - long length = amount; - while (length > 0) { - int read = (int) Math.min(length, Integer.MAX_VALUE); - read = aux.target.read(buffer, 0, Math.min(read, buffer.length)); - - if (read < 1) { - amount -= length; - break; - } - - out.writeProof(buffer, read); - length -= read; - } - - if (underflow) { - if (out.offset >= out.length) { - // calculate the aux underflow pointer - if (aux.offset < amount) { - out.offset += aux.offset; - aux.offset = 0; - out.target.seek(out.offset); - } else { - aux.offset -= amount; - out.offset = out.length + amount; - } - } else { - aux.offset = 0; - } - } else { - out.offset += amount; - aux.offset -= amount; - } - - out.length += amount; - - if (out.length > maxLengthKnown) { - maxLengthKnown = out.length; - } - - if (amount < aux.length) { - // move the excess data to the beginning of the file - long readOffset = amount; - long writeOffset = 0; - - aux.length -= amount; - length = aux.length; - while (length > 0) { - int read = (int) Math.min(length, Integer.MAX_VALUE); - read = aux.target.read(buffer, 0, Math.min(read, buffer.length)); - - aux.target.seek(writeOffset); - aux.writeProof(buffer, read); - - writeOffset += read; - readOffset += read; - length -= read; - - aux.target.seek(readOffset); - } - - aux.target.setLength(aux.length); - return; - } - - if (aux.length > THRESHOLD_AUX_LENGTH) { - aux.target.setLength(THRESHOLD_AUX_LENGTH);// or setLength(0); - } - - aux.reset(); - } - - /** - * Flush any buffer and close the output file. Use this method if the - * operation is successful - * - * @return the final length of the file - * @throws IOException if an I/O error occurs - */ - public long finalizeFile() throws IOException { - flushAuxiliar(aux.length); - - out.flush(); - - // change file length (if required) - long length = Math.max(maxLengthKnown, out.length); - if (length != out.target.length()) { - out.target.setLength(length); - } - - close(); - - return length; - } - - /** - * Close the file without flushing any buffer - */ - @Override - public void close() { - if (out != null) { - out.close(); - out = null; - } - if (aux != null) { - aux.close(); - aux = null; - } - } - - @Override - public void write(byte b) throws IOException { - write(new byte[]{b}, 0, 1); - } - - @Override - public void write(byte[] b) throws IOException { - write(b, 0, b.length); - } - - @Override - public void write(byte[] b, int off, int len) throws IOException { - if (len == 0) { - return; - } - - long available; - long offsetOut = out.getOffset(); - long offsetAux = aux.getOffset(); - long end = callback.check(); - - if (end == -1) { - available = Integer.MAX_VALUE; - } else if (end < offsetOut) { - throw new IOException("The reported offset is invalid: " + end + "<" + offsetOut); - } else { - available = end - offsetOut; - } - - boolean usingAux = aux.length > 0 && offsetOut >= out.length; - boolean underflow = offsetAux < aux.length || offsetOut < out.length; - - if (usingAux) { - // before continue calculate the final length of aux - long length = offsetAux + len; - if (underflow) { - if (aux.length > length) { - length = aux.length;// the length is not changed - } - } else { - length = aux.length + len; - } - - aux.write(b, off, len); - - if (length >= THRESHOLD_AUX_LENGTH && length <= available) { - flushAuxiliar(available); - } - } else { - if (underflow) { - available = out.length - offsetOut; - } - - int length = Math.min(len, (int) Math.min(Integer.MAX_VALUE, available)); - out.write(b, off, length); - - len -= length; - off += length; - - if (len > 0) { - aux.write(b, off, len); - } - } - - if (onProgress != null) { - long absoluteOffset = out.getOffset() + aux.getOffset(); - if (absoluteOffset > reportPosition) { - reportPosition = absoluteOffset + NOTIFY_BYTES_INTERVAL; - onProgress.report(absoluteOffset); - } - } - } - - @Override - public void flush() throws IOException { - aux.flush(); - out.flush(); - - long total = out.length + aux.length; - if (total > maxLengthKnown) { - maxLengthKnown = total;// save the current file length in case the method {@code rewind()} is called - } - } - - @Override - public long skip(long amount) throws IOException { - seek(out.getOffset() + aux.getOffset() + amount); - return amount; - } - - @Override - public void rewind() throws IOException { - if (onProgress != null) { - onProgress.report(0);// rollback the whole progress - } - - seek(0); - - reportPosition = NOTIFY_BYTES_INTERVAL; - } - - @Override - public void seek(long offset) throws IOException { - long total = out.length + aux.length; - - if (offset == total) { - // do not ignore the seek offset if a underflow exists - long relativeOffset = out.getOffset() + aux.getOffset(); - if (relativeOffset == total) { - return; - } - } - - // flush everything, avoid any underflow - flush(); - - if (offset < 0 || offset > total) { - throw new IOException("desired offset is outside of range=0-" + total + " offset=" + offset); - } - - if (offset > out.length) { - out.seek(out.length); - aux.seek(offset - out.length); - } else { - out.seek(offset); - aux.seek(0); - } - } - - @Override - public boolean isClosed() { - return out == null; - } - - @Override - public boolean canRewind() { - return true; - } - - @Override - public boolean canWrite() { - return true; - } - - @Override - public boolean canSeek() { - return true; - } - - // - @Override - public boolean canRead() { - return false; - } - - @Override - public int read() { - throw new UnsupportedOperationException("write-only"); - } - - @Override - public int read(byte[] buffer - ) { - throw new UnsupportedOperationException("write-only"); - } - - @Override - public int read(byte[] buffer, int offset, int count - ) { - throw new UnsupportedOperationException("write-only"); - } - - @Override - public long available() { - throw new UnsupportedOperationException("write-only"); - } - // - - public interface OffsetChecker { - - /** - * Checks the amount of available space ahead - * - * @return absolute offset in the file where no more data SHOULD NOT be - * written. If the value is -1 the whole file will be used - */ - long check(); - } - - public interface WriteErrorHandle { - - /** - * Attempts to handle a I/O exception - * - * @param err the cause - * @return {@code true} to retry and continue, otherwise, {@code false} - * and throw the exception - */ - boolean handle(Exception err); - } - - class BufferedFile { - - final SharpStream target; - - private long offset; - long length; - - private byte[] queue = new byte[QUEUE_BUFFER_SIZE]; - private int queueSize; - - BufferedFile(File file) throws FileNotFoundException { - this.target = new FileStream(file); - } - - BufferedFile(SharpStream target) { - this.target = target; - } - - long getOffset() { - return offset + queueSize;// absolute offset in the file - } - - void close() { - queue = null; - target.close(); - } - - void write(byte[] b, int off, int len) throws IOException { - while (len > 0) { - // if the queue is full, the method available() will flush the queue - int read = Math.min(available(), len); - - // enqueue incoming buffer - System.arraycopy(b, off, queue, queueSize, read); - queueSize += read; - - len -= read; - off += read; - } - - long total = offset + queueSize; - if (total > length) { - length = total;// save length - } - } - - void flush() throws IOException { - writeProof(queue, queueSize); - offset += queueSize; - queueSize = 0; - } - - protected void rewind() throws IOException { - offset = 0; - target.seek(0); - } - - int available() throws IOException { - if (queueSize >= queue.length) { - flush(); - return queue.length; - } - - return queue.length - queueSize; - } - - void reset() throws IOException { - offset = 0; - length = 0; - target.seek(0); - } - - void seek(long absoluteOffset) throws IOException { - if (absoluteOffset == offset) { - return;// nothing to do - } - offset = absoluteOffset; - target.seek(absoluteOffset); - } - - void writeProof(byte[] buffer, int length) throws IOException { - if (onWriteError == null) { - target.write(buffer, 0, length); - return; - } - - while (true) { - try { - target.write(buffer, 0, length); - return; - } catch (Exception e) { - if (!onWriteError.handle(e)) { - throw e;// give up - } - } - } - } - - @NonNull - @Override - public String toString() { - String absLength; - - try { - absLength = Long.toString(target.length()); - } catch (IOException e) { - absLength = "[" + e.getLocalizedMessage() + "]"; - } - - return String.format( - "offset=%s length=%s queue=%s absLength=%s", - offset, length, queueSize, absLength - ); - } - } -} diff --git a/app/src/main/java/us/shandian/giga/io/FileStream.java b/app/src/main/java/us/shandian/giga/io/FileStream.java deleted file mode 100644 index bbc56b20c21..00000000000 --- a/app/src/main/java/us/shandian/giga/io/FileStream.java +++ /dev/null @@ -1,131 +0,0 @@ -package us.shandian.giga.io; - -import androidx.annotation.NonNull; - -import org.schabi.newpipe.streams.io.SharpStream; - -import java.io.File; -import java.io.FileNotFoundException; -import java.io.IOException; -import java.io.RandomAccessFile; - -/** - * @author kapodamy - */ -public class FileStream extends SharpStream { - - public RandomAccessFile source; - - public FileStream(@NonNull File target) throws FileNotFoundException { - this.source = new RandomAccessFile(target, "rw"); - } - - public FileStream(@NonNull String path) throws FileNotFoundException { - this.source = new RandomAccessFile(path, "rw"); - } - - @Override - public int read() throws IOException { - return source.read(); - } - - @Override - public int read(byte[] b) throws IOException { - return source.read(b); - } - - @Override - public int read(byte[] b, int off, int len) throws IOException { - return source.read(b, off, len); - } - - @Override - public long skip(long pos) throws IOException { - return source.skipBytes((int) pos); - } - - @Override - public long available() { - try { - return source.length() - source.getFilePointer(); - } catch (IOException e) { - return 0; - } - } - - @Override - public void close() { - if (source == null) return; - try { - source.close(); - } catch (IOException err) { - // nothing to do - } - source = null; - } - - @Override - public boolean isClosed() { - return source == null; - } - - @Override - public void rewind() throws IOException { - source.seek(0); - } - - @Override - public boolean canRewind() { - return true; - } - - @Override - public boolean canRead() { - return true; - } - - @Override - public boolean canWrite() { - return true; - } - - @Override - public boolean canSeek() { - return true; - } - - @Override - public boolean canSetLength() { - return true; - } - - @Override - public void write(byte value) throws IOException { - source.write(value); - } - - @Override - public void write(byte[] buffer) throws IOException { - source.write(buffer); - } - - @Override - public void write(byte[] buffer, int offset, int count) throws IOException { - source.write(buffer, offset, count); - } - - @Override - public void setLength(long length) throws IOException { - source.setLength(length); - } - - @Override - public void seek(long offset) throws IOException { - source.seek(offset); - } - - @Override - public long length() throws IOException { - return source.length(); - } -} diff --git a/app/src/main/java/us/shandian/giga/io/FileStreamSAF.java b/app/src/main/java/us/shandian/giga/io/FileStreamSAF.java deleted file mode 100644 index b7dd0a103e4..00000000000 --- a/app/src/main/java/us/shandian/giga/io/FileStreamSAF.java +++ /dev/null @@ -1,150 +0,0 @@ -package us.shandian.giga.io; - -import android.content.ContentResolver; -import android.net.Uri; -import android.os.ParcelFileDescriptor; -import android.util.Log; - -import androidx.annotation.NonNull; - -import org.schabi.newpipe.streams.io.SharpStream; - -import java.io.FileInputStream; -import java.io.FileOutputStream; -import java.io.IOException; -import java.nio.channels.FileChannel; - -public class FileStreamSAF extends SharpStream { - - private final FileInputStream in; - private final FileOutputStream out; - private final FileChannel channel; - private final ParcelFileDescriptor file; - - private boolean disposed; - - public FileStreamSAF(@NonNull ContentResolver contentResolver, Uri fileUri) throws IOException { - // Notes: - // the file must exists first - // ¡read-write mode must allow seek! - // It is not guaranteed to work with files in the cloud (virtual files), tested in local storage devices - - file = contentResolver.openFileDescriptor(fileUri, "rw"); - - if (file == null) { - throw new IOException("Cannot get the ParcelFileDescriptor for " + fileUri.toString()); - } - - in = new FileInputStream(file.getFileDescriptor()); - out = new FileOutputStream(file.getFileDescriptor()); - channel = out.getChannel();// or use in.getChannel() - } - - @Override - public int read() throws IOException { - return in.read(); - } - - @Override - public int read(byte[] buffer) throws IOException { - return in.read(buffer); - } - - @Override - public int read(byte[] buffer, int offset, int count) throws IOException { - return in.read(buffer, offset, count); - } - - @Override - public long skip(long amount) throws IOException { - return in.skip(amount);// ¿or use channel.position(channel.position() + amount)? - } - - @Override - public long available() { - try { - return in.available(); - } catch (IOException e) { - return 0;// ¡but not -1! - } - } - - @Override - public void rewind() throws IOException { - seek(0); - } - - @Override - public void close() { - try { - disposed = true; - - file.close(); - in.close(); - out.close(); - channel.close(); - } catch (IOException e) { - Log.e("FileStreamSAF", "close() error", e); - } - } - - @Override - public boolean isClosed() { - return disposed; - } - - @Override - public boolean canRewind() { - return true; - } - - @Override - public boolean canRead() { - return true; - } - - @Override - public boolean canWrite() { - return true; - } - - @Override - public boolean canSetLength() { - return true; - } - - @Override - public boolean canSeek() { - return true; - } - - @Override - public void write(byte value) throws IOException { - out.write(value); - } - - @Override - public void write(byte[] buffer) throws IOException { - out.write(buffer); - } - - @Override - public void write(byte[] buffer, int offset, int count) throws IOException { - out.write(buffer, offset, count); - } - - @Override - public void setLength(long length) throws IOException { - channel.truncate(length); - } - - @Override - public void seek(long offset) throws IOException { - channel.position(offset); - } - - @Override - public long length() throws IOException { - return channel.size(); - } -} diff --git a/app/src/main/java/us/shandian/giga/io/ProgressReport.java b/app/src/main/java/us/shandian/giga/io/ProgressReport.java deleted file mode 100644 index e382747f6b3..00000000000 --- a/app/src/main/java/us/shandian/giga/io/ProgressReport.java +++ /dev/null @@ -1,11 +0,0 @@ -package us.shandian.giga.io; - -public interface ProgressReport { - - /** - * Report the size of the new file - * - * @param progress the new size - */ - void report(long progress); -} \ No newline at end of file