mirror of
https://github.com/ArcaneChat/android.git
synced 2026-07-03 14:05:24 +02:00
Merge pull request #3215 from deltachat/adb/issue-1791
stop using jcenter
This commit is contained in:
+7
-9
@@ -7,11 +7,9 @@ repositories {
|
||||
google()
|
||||
mavenCentral()
|
||||
maven {
|
||||
// Used only for PhotoView
|
||||
url "https://www.jitpack.io"
|
||||
name 'JitPack Github wrapper'
|
||||
}
|
||||
jcenter()
|
||||
}
|
||||
|
||||
android {
|
||||
@@ -35,7 +33,7 @@ android {
|
||||
applicationId "com.b44t.messenger"
|
||||
multiDexEnabled true
|
||||
|
||||
minSdkVersion 16
|
||||
minSdkVersion 19
|
||||
targetSdkVersion 33
|
||||
|
||||
vectorDrawables.useSupportLibrary = true
|
||||
@@ -164,10 +162,11 @@ dependencies {
|
||||
implementation 'androidx.work:work-runtime:2.8.1'
|
||||
implementation 'androidx.emoji2:emoji2-emojipicker:1.4.0'
|
||||
implementation 'com.google.guava:guava:29.0-android'
|
||||
implementation 'com.google.android.exoplayer:exoplayer-core:2.9.6' // plays video and audio
|
||||
implementation 'com.google.android.exoplayer:exoplayer-ui:2.9.6'
|
||||
implementation 'com.google.android.exoplayer:exoplayer-core:2.19.1' // plays video and audio
|
||||
implementation 'com.google.android.exoplayer:exoplayer-ui:2.19.1'
|
||||
implementation 'androidx.constraintlayout:constraintlayout:2.1.4'
|
||||
implementation 'com.journeyapps:zxing-android-embedded:3.4.0' // QR Code scanner
|
||||
implementation 'com.google.zxing:core:3.3.0' // fixed version to support SDK<24
|
||||
implementation ('com.journeyapps:zxing-android-embedded:4.3.0') { transitive = false } // QR Code scanner
|
||||
implementation 'com.fasterxml.jackson.core:jackson-databind:2.11.1' // used as JSON library
|
||||
implementation 'com.google.code.gson:gson:2.9.1' // used as JSON library. Don't upgrade to 2.10.1: https://github.com/deltachat/deltachat-android/pull/2610
|
||||
implementation "me.leolin:ShortcutBadger:1.1.16" // display messagecount on the home screen icon.
|
||||
@@ -182,16 +181,15 @@ dependencies {
|
||||
implementation 'com.pnikosis:materialish-progress:1.5' // used only in the "Progress Wheel" in Share Activity.
|
||||
implementation 'com.soundcloud.android:android-crop:1.0.1@aar' // used for profile and group avatar selection in Android SDK<19
|
||||
implementation 'com.nineoldandroids:library:2.4.0' // DEPRECATED! Used to slide in the half-camera.
|
||||
implementation 'mobi.upod:time-duration-picker:1.1.3' // Used to pick the time for inactivity.
|
||||
implementation 'com.amulyakhare:com.amulyakhare.textdrawable:1.0.1' // number of unread messages,
|
||||
implementation 'com.github.amulyakhare:TextDrawable:558677ea31' // number of unread messages,
|
||||
// the one-letter circle for the contacts (when there is not avatar) and a white background.
|
||||
implementation 'com.googlecode.mp4parser:isoparser:1.0.6' // MP4 recoding; upgrading eg. to 1.1.22 breaks recoding, however, i have not investigated further, just reset to 1.0.6
|
||||
implementation ('com.davemorrissey.labs:subsampling-scale-image-view:3.6.0') { // for the zooming on photos / media
|
||||
exclude group: 'com.android.support', module: 'support-annotations'
|
||||
}
|
||||
implementation 'com.annimon:stream:1.1.8' // brings future java streams api to SDK Version < 24
|
||||
implementation 'com.codewaves.stickyheadergrid:stickyheadergrid:0.9.4' // glues the current time segment text in the gallery to the top.
|
||||
|
||||
implementation 'com.getkeepsafe.relinker:relinker:1.4.4' // needed to avoid safe-content-resolver-v14 trying to fetch older non-existing version
|
||||
// Replacement for ContentResolver
|
||||
// that protects against the Surreptitious Sharing attack.
|
||||
// <https://github.com/cketti/SafeContentResolver>
|
||||
|
||||
@@ -0,0 +1,612 @@
|
||||
package com.codewaves.stickyheadergrid;
|
||||
|
||||
import static androidx.recyclerview.widget.RecyclerView.NO_POSITION;
|
||||
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
|
||||
import java.security.InvalidParameterException;
|
||||
import java.util.ArrayList;
|
||||
|
||||
/**
|
||||
* Created by Sergej Kravcenko on 4/24/2017.
|
||||
* Copyright (c) 2017 Sergej Kravcenko
|
||||
*/
|
||||
|
||||
@SuppressWarnings({"unused", "WeakerAccess"})
|
||||
public abstract class StickyHeaderGridAdapter extends RecyclerView.Adapter<StickyHeaderGridAdapter.ViewHolder> {
|
||||
public static final String TAG = "StickyHeaderGridAdapter";
|
||||
|
||||
public static final int TYPE_HEADER = 0;
|
||||
public static final int TYPE_ITEM = 1;
|
||||
|
||||
private ArrayList<Section> mSections;
|
||||
private int[] mSectionIndices;
|
||||
private int mTotalItemNumber;
|
||||
|
||||
@SuppressWarnings("WeakerAccess")
|
||||
public static class ViewHolder extends RecyclerView.ViewHolder {
|
||||
public ViewHolder(View itemView) {
|
||||
super(itemView);
|
||||
}
|
||||
|
||||
public boolean isHeader() {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
public int getSectionItemViewType() {
|
||||
return StickyHeaderGridAdapter.externalViewType(getItemViewType());
|
||||
}
|
||||
}
|
||||
|
||||
public static class ItemViewHolder extends ViewHolder {
|
||||
public ItemViewHolder(View itemView) {
|
||||
super(itemView);
|
||||
}
|
||||
}
|
||||
|
||||
public static class HeaderViewHolder extends ViewHolder {
|
||||
public HeaderViewHolder(View itemView) {
|
||||
super(itemView);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isHeader() {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
private static class Section {
|
||||
private int position;
|
||||
private int itemNumber;
|
||||
private int length;
|
||||
}
|
||||
|
||||
private void calculateSections() {
|
||||
mSections = new ArrayList<>();
|
||||
|
||||
int total = 0;
|
||||
int sectionCount = getSectionCount();
|
||||
for (int s = 0; s < sectionCount; s++) {
|
||||
final Section section = new Section();
|
||||
section.position = total;
|
||||
section.itemNumber = getSectionItemCount(s);
|
||||
section.length = section.itemNumber + 1;
|
||||
mSections.add(section);
|
||||
|
||||
total += section.length;
|
||||
}
|
||||
mTotalItemNumber = total;
|
||||
|
||||
total = 0;
|
||||
mSectionIndices = new int[mTotalItemNumber];
|
||||
for (int s = 0; s < sectionCount; s++) {
|
||||
final Section section = mSections.get(s);
|
||||
for (int i = 0; i < section.length; i++) {
|
||||
mSectionIndices[total + i] = s;
|
||||
}
|
||||
total += section.length;
|
||||
}
|
||||
}
|
||||
|
||||
protected int getItemViewInternalType(int position) {
|
||||
final int section = getAdapterPositionSection(position);
|
||||
final Section sectionObject = mSections.get(section);
|
||||
final int sectionPosition = position - sectionObject.position;
|
||||
|
||||
return getItemViewInternalType(section, sectionPosition);
|
||||
}
|
||||
|
||||
private int getItemViewInternalType(int section, int position) {
|
||||
return position == 0 ? TYPE_HEADER : TYPE_ITEM;
|
||||
}
|
||||
|
||||
static private int internalViewType(int type) {
|
||||
return type & 0xFF;
|
||||
}
|
||||
|
||||
static private int externalViewType(int type) {
|
||||
return type >> 8;
|
||||
}
|
||||
|
||||
@Override
|
||||
final public int getItemCount() {
|
||||
if (mSections == null) {
|
||||
calculateSections();
|
||||
}
|
||||
return mTotalItemNumber;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
final public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
|
||||
final int internalType = internalViewType(viewType);
|
||||
final int externalType = externalViewType(viewType);
|
||||
|
||||
switch (internalType) {
|
||||
case TYPE_HEADER:
|
||||
return onCreateHeaderViewHolder(parent, externalType);
|
||||
case TYPE_ITEM:
|
||||
return onCreateItemViewHolder(parent, externalType);
|
||||
default:
|
||||
throw new InvalidParameterException("Invalid viewType: " + viewType);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
final public void onBindViewHolder(@NonNull ViewHolder holder, int position) {
|
||||
if (mSections == null) {
|
||||
calculateSections();
|
||||
}
|
||||
|
||||
final int section = mSectionIndices[position];
|
||||
final int internalType = internalViewType(holder.getItemViewType());
|
||||
final int externalType = externalViewType(holder.getItemViewType());
|
||||
|
||||
switch (internalType) {
|
||||
case TYPE_HEADER:
|
||||
onBindHeaderViewHolder((HeaderViewHolder)holder, section);
|
||||
break;
|
||||
case TYPE_ITEM:
|
||||
final ItemViewHolder itemHolder = (ItemViewHolder)holder;
|
||||
final int offset = getItemSectionOffset(section, position);
|
||||
onBindItemViewHolder((ItemViewHolder)holder, section, offset);
|
||||
break;
|
||||
default:
|
||||
throw new InvalidParameterException("invalid viewType: " + internalType);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
final public int getItemViewType(int position) {
|
||||
final int section = getAdapterPositionSection(position);
|
||||
final Section sectionObject = mSections.get(section);
|
||||
final int sectionPosition = position - sectionObject.position;
|
||||
final int internalType = getItemViewInternalType(section, sectionPosition);
|
||||
int externalType = 0;
|
||||
|
||||
switch (internalType) {
|
||||
case TYPE_HEADER:
|
||||
externalType = getSectionHeaderViewType(section);
|
||||
break;
|
||||
case TYPE_ITEM:
|
||||
externalType = getSectionItemViewType(section, sectionPosition - 1);
|
||||
break;
|
||||
}
|
||||
|
||||
return ((externalType & 0xFF) << 8) | (internalType & 0xFF);
|
||||
}
|
||||
|
||||
// Helpers
|
||||
private int getItemSectionHeaderPosition(int position) {
|
||||
return getSectionHeaderPosition(getAdapterPositionSection(position));
|
||||
}
|
||||
|
||||
private int getAdapterPosition(int section, int offset) {
|
||||
if (mSections == null) {
|
||||
calculateSections();
|
||||
}
|
||||
|
||||
if (section < 0) {
|
||||
throw new IndexOutOfBoundsException("section " + section + " < 0");
|
||||
}
|
||||
|
||||
if (section >= mSections.size()) {
|
||||
throw new IndexOutOfBoundsException("section " + section + " >=" + mSections.size());
|
||||
}
|
||||
|
||||
final Section sectionObject = mSections.get(section);
|
||||
return sectionObject.position + offset;
|
||||
}
|
||||
|
||||
/**
|
||||
* Given a <code>section</code> and an adapter <code>position</code> get the offset of an item
|
||||
* inside <code>section</code>.
|
||||
*
|
||||
* @param section section to query
|
||||
* @param position adapter position
|
||||
* @return The item offset inside the section.
|
||||
*/
|
||||
public int getItemSectionOffset(int section, int position) {
|
||||
if (mSections == null) {
|
||||
calculateSections();
|
||||
}
|
||||
|
||||
if (section < 0) {
|
||||
throw new IndexOutOfBoundsException("section " + section + " < 0");
|
||||
}
|
||||
|
||||
if (section >= mSections.size()) {
|
||||
throw new IndexOutOfBoundsException("section " + section + " >=" + mSections.size());
|
||||
}
|
||||
|
||||
final Section sectionObject = mSections.get(section);
|
||||
final int localPosition = position - sectionObject.position;
|
||||
if (localPosition >= sectionObject.length) {
|
||||
throw new IndexOutOfBoundsException("localPosition: " + localPosition + " >=" + sectionObject.length);
|
||||
}
|
||||
|
||||
return localPosition - 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the section index having item or header with provided
|
||||
* provider <code>position</code>.
|
||||
*
|
||||
* @param position adapter position
|
||||
* @return The section containing provided adapter position.
|
||||
*/
|
||||
public int getAdapterPositionSection(int position) {
|
||||
if (mSections == null) {
|
||||
calculateSections();
|
||||
}
|
||||
|
||||
if (getItemCount() == 0) {
|
||||
return NO_POSITION;
|
||||
}
|
||||
|
||||
if (position < 0) {
|
||||
throw new IndexOutOfBoundsException("position " + position + " < 0");
|
||||
}
|
||||
|
||||
if (position >= getItemCount()) {
|
||||
throw new IndexOutOfBoundsException("position " + position + " >=" + getItemCount());
|
||||
}
|
||||
|
||||
return mSectionIndices[position];
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the adapter position for given <code>section</code> header. Use
|
||||
* this only for {@link RecyclerView#scrollToPosition(int)} or similar functions.
|
||||
* Never directly manipulate adapter items using this position.
|
||||
*
|
||||
* @param section section to query
|
||||
* @return The adapter position.
|
||||
*/
|
||||
public int getSectionHeaderPosition(int section) {
|
||||
return getAdapterPosition(section, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the adapter position for given <code>section</code> and
|
||||
* <code>offset</code>. Use this only for {@link RecyclerView#scrollToPosition(int)}
|
||||
* or similar functions. Never directly manipulate adapter items using this position.
|
||||
*
|
||||
* @param section section to query
|
||||
* @param position item position inside the <code>section</code>
|
||||
* @return The adapter position.
|
||||
*/
|
||||
public int getSectionItemPosition(int section, int position) {
|
||||
return getAdapterPosition(section, position + 1);
|
||||
}
|
||||
|
||||
// Overrides
|
||||
/**
|
||||
* Returns the total number of sections in the data set held by the adapter.
|
||||
*
|
||||
* @return The total number of section in this adapter.
|
||||
*/
|
||||
public int getSectionCount() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the number of items in the <code>section</code>.
|
||||
*
|
||||
* @param section section to query
|
||||
* @return The total number of items in the <code>section</code>.
|
||||
*/
|
||||
public int getSectionItemCount(int section) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the view type of the <code>section</code> header for the purposes
|
||||
* of view recycling.
|
||||
*
|
||||
* <p>The default implementation of this method returns 0, making the assumption of
|
||||
* a single view type for the headers. Unlike ListView adapters, types need not
|
||||
* be contiguous. Consider using id resources to uniquely identify item view types.
|
||||
*
|
||||
* @param section section to query
|
||||
* @return integer value identifying the type of the view needed to represent the header in
|
||||
* <code>section</code>. Type codes need not be contiguous.
|
||||
*/
|
||||
public int getSectionHeaderViewType(int section) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the view type of the item at <code>position</code> in <code>section</code> for
|
||||
* the purposes of view recycling.
|
||||
*
|
||||
* <p>The default implementation of this method returns 0, making the assumption of
|
||||
* a single view type for the adapter. Unlike ListView adapters, types need not
|
||||
* be contiguous. Consider using id resources to uniquely identify item view types.
|
||||
*
|
||||
* @param section section to query
|
||||
* @param offset section position to query
|
||||
* @return integer value identifying the type of the view needed to represent the item at
|
||||
* <code>position</code> in <code>section</code>. Type codes need not be
|
||||
* contiguous.
|
||||
*/
|
||||
public int getSectionItemViewType(int section, int offset) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if header in <code>section</code> is sticky.
|
||||
*
|
||||
* @param section section to query
|
||||
* @return true if <code>section</code> header is sticky.
|
||||
*/
|
||||
public boolean isSectionHeaderSticky(int section) {
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when RecyclerView needs a new {@link HeaderViewHolder} of the given type to represent
|
||||
* a header.
|
||||
* <p>
|
||||
* This new HeaderViewHolder should be constructed with a new View that can represent the headers
|
||||
* of the given type. You can either create a new View manually or inflate it from an XML
|
||||
* layout file.
|
||||
* <p>
|
||||
* The new HeaderViewHolder will be used to display items of the adapter using
|
||||
* {@link #onBindHeaderViewHolder(HeaderViewHolder, int)}. Since it will be re-used to display
|
||||
* different items in the data set, it is a good idea to cache references to sub views of
|
||||
* the View to avoid unnecessary {@link View#findViewById(int)} calls.
|
||||
*
|
||||
* @param parent The ViewGroup into which the new View will be added after it is bound to
|
||||
* an adapter position.
|
||||
* @param headerType The view type of the new View.
|
||||
*
|
||||
* @return A new ViewHolder that holds a View of the given view type.
|
||||
* @see #getSectionHeaderViewType(int)
|
||||
* @see #onBindHeaderViewHolder(HeaderViewHolder, int)
|
||||
*/
|
||||
public abstract HeaderViewHolder onCreateHeaderViewHolder(ViewGroup parent, int headerType);
|
||||
|
||||
/**
|
||||
* Called when RecyclerView needs a new {@link ItemViewHolder} of the given type to represent
|
||||
* an item.
|
||||
* <p>
|
||||
* This new ViewHolder should be constructed with a new View that can represent the items
|
||||
* of the given type. You can either create a new View manually or inflate it from an XML
|
||||
* layout file.
|
||||
* <p>
|
||||
* The new ViewHolder will be used to display items of the adapter using
|
||||
* {@link #onBindItemViewHolder(ItemViewHolder, int, int)}. Since it will be re-used to display
|
||||
* different items in the data set, it is a good idea to cache references to sub views of
|
||||
* the View to avoid unnecessary {@link View#findViewById(int)} calls.
|
||||
*
|
||||
* @param parent The ViewGroup into which the new View will be added after it is bound to
|
||||
* an adapter position.
|
||||
* @param itemType The view type of the new View.
|
||||
*
|
||||
* @return A new ViewHolder that holds a View of the given view type.
|
||||
* @see #getSectionItemViewType(int, int)
|
||||
* @see #onBindItemViewHolder(ItemViewHolder, int, int)
|
||||
*/
|
||||
public abstract ItemViewHolder onCreateItemViewHolder(ViewGroup parent, int itemType);
|
||||
|
||||
/**
|
||||
* Called by RecyclerView to display the data at the specified position. This method should
|
||||
* update the contents of the {@link HeaderViewHolder#itemView} to reflect the header at the given
|
||||
* position.
|
||||
* <p>
|
||||
* Note that unlike {@link android.widget.ListView}, RecyclerView will not call this method
|
||||
* again if the position of the header changes in the data set unless the header itself is
|
||||
* invalidated or the new position cannot be determined. For this reason, you should only
|
||||
* use the <code>section</code> parameter while acquiring the
|
||||
* related header data inside this method and should not keep a copy of it. If you need the
|
||||
* position of a header later on (e.g. in a click listener), use
|
||||
* {@link HeaderViewHolder#getAdapterPosition()} which will have the updated adapter
|
||||
* position. Then you can use {@link #getAdapterPositionSection(int)} to get section index.
|
||||
*
|
||||
*
|
||||
* @param viewHolder The ViewHolder which should be updated to represent the contents of the
|
||||
* header at the given position in the data set.
|
||||
* @param section The index of the section.
|
||||
*/
|
||||
public abstract void onBindHeaderViewHolder(HeaderViewHolder viewHolder, int section);
|
||||
|
||||
/**
|
||||
* Called by RecyclerView to display the data at the specified position. This method should
|
||||
* update the contents of the {@link ItemViewHolder#itemView} to reflect the item at the given
|
||||
* position.
|
||||
* <p>
|
||||
* Note that unlike {@link android.widget.ListView}, RecyclerView will not call this method
|
||||
* again if the position of the item changes in the data set unless the item itself is
|
||||
* invalidated or the new position cannot be determined. For this reason, you should only
|
||||
* use the <code>offset</code> and <code>section</code> parameters while acquiring the
|
||||
* related data item inside this method and should not keep a copy of it. If you need the
|
||||
* position of an item later on (e.g. in a click listener), use
|
||||
* {@link ItemViewHolder#getAdapterPosition()} which will have the updated adapter
|
||||
* position. Then you can use {@link #getAdapterPositionSection(int)} and
|
||||
* {@link #getItemSectionOffset(int, int)}
|
||||
*
|
||||
*
|
||||
* @param viewHolder The ViewHolder which should be updated to represent the contents of the
|
||||
* item at the given position in the data set.
|
||||
* @param section The index of the section.
|
||||
* @param offset The position of the item within the section.
|
||||
*/
|
||||
public abstract void onBindItemViewHolder(ItemViewHolder viewHolder, int section, int offset);
|
||||
|
||||
// Notify
|
||||
/**
|
||||
* Notify any registered observers that the data set has changed.
|
||||
*
|
||||
* <p>There are two different classes of data change events, item changes and structural
|
||||
* changes. Item changes are when a single item has its data updated but no positional
|
||||
* changes have occurred. Structural changes are when items are inserted, removed or moved
|
||||
* within the data set.</p>
|
||||
*
|
||||
* <p>This event does not specify what about the data set has changed, forcing
|
||||
* any observers to assume that all existing items and structure may no longer be valid.
|
||||
* LayoutManagers will be forced to fully rebind and relayout all visible views.</p>
|
||||
*
|
||||
* <p><code>RecyclerView</code> will attempt to synthesize visible structural change events
|
||||
* for adapters that report that they have {@link #hasStableIds() stable IDs} when
|
||||
* this method is used. This can help for the purposes of animation and visual
|
||||
* object persistence but individual item views will still need to be rebound
|
||||
* and relaid out.</p>
|
||||
*
|
||||
* <p>If you are writing an adapter it will always be more efficient to use the more
|
||||
* specific change events if you can. Rely on <code>notifyDataSetChanged()</code>
|
||||
* as a last resort.</p>
|
||||
*
|
||||
* @see #notifySectionDataSetChanged(int)
|
||||
* @see #notifySectionHeaderChanged(int)
|
||||
* @see #notifySectionItemChanged(int, int)
|
||||
* @see #notifySectionInserted(int)
|
||||
* @see #notifySectionItemInserted(int, int)
|
||||
* @see #notifySectionItemRangeInserted(int, int, int)
|
||||
* @see #notifySectionRemoved(int)
|
||||
* @see #notifySectionItemRemoved(int, int)
|
||||
* @see #notifySectionItemRangeRemoved(int, int, int)
|
||||
*/
|
||||
public void notifyAllSectionsDataSetChanged() {
|
||||
calculateSections();
|
||||
notifyDataSetChanged();
|
||||
}
|
||||
|
||||
public void notifySectionDataSetChanged(int section) {
|
||||
calculateSections();
|
||||
if (mSections == null) {
|
||||
notifyAllSectionsDataSetChanged();
|
||||
}
|
||||
else {
|
||||
final Section sectionObject = mSections.get(section);
|
||||
notifyItemRangeChanged(sectionObject.position, sectionObject.length);
|
||||
}
|
||||
}
|
||||
|
||||
public void notifySectionHeaderChanged(int section) {
|
||||
calculateSections();
|
||||
if (mSections == null) {
|
||||
notifyAllSectionsDataSetChanged();
|
||||
}
|
||||
else {
|
||||
final Section sectionObject = mSections.get(section);
|
||||
notifyItemRangeChanged(sectionObject.position, 1);
|
||||
}
|
||||
}
|
||||
|
||||
public void notifySectionItemChanged(int section, int position) {
|
||||
calculateSections();
|
||||
if (mSections == null) {
|
||||
notifyAllSectionsDataSetChanged();
|
||||
}
|
||||
else {
|
||||
final Section sectionObject = mSections.get(section);
|
||||
|
||||
if (position >= sectionObject.itemNumber) {
|
||||
throw new IndexOutOfBoundsException("Invalid index " + position + ", size is " + sectionObject.itemNumber);
|
||||
}
|
||||
|
||||
notifyItemChanged(sectionObject.position + position + 1);
|
||||
}
|
||||
}
|
||||
|
||||
public void notifySectionInserted(int section) {
|
||||
calculateSections();
|
||||
if (mSections == null) {
|
||||
notifyAllSectionsDataSetChanged();
|
||||
}
|
||||
else {
|
||||
final Section sectionObject = mSections.get(section);
|
||||
notifyItemRangeInserted(sectionObject.position, sectionObject.length);
|
||||
}
|
||||
}
|
||||
|
||||
public void notifySectionItemInserted(int section, int position) {
|
||||
calculateSections();
|
||||
if (mSections == null) {
|
||||
notifyAllSectionsDataSetChanged();
|
||||
}
|
||||
else {
|
||||
final Section sectionObject = mSections.get(section);
|
||||
|
||||
if (position < 0 || position >= sectionObject.itemNumber) {
|
||||
throw new IndexOutOfBoundsException("Invalid index " + position + ", size is " + sectionObject.itemNumber);
|
||||
}
|
||||
|
||||
notifyItemInserted(sectionObject.position + position + 1);
|
||||
}
|
||||
}
|
||||
|
||||
public void notifySectionItemRangeInserted(int section, int position, int count) {
|
||||
calculateSections();
|
||||
if (mSections == null) {
|
||||
notifyAllSectionsDataSetChanged();
|
||||
}
|
||||
else {
|
||||
final Section sectionObject = mSections.get(section);
|
||||
|
||||
if (position < 0 || position >= sectionObject.itemNumber) {
|
||||
throw new IndexOutOfBoundsException("Invalid index " + position + ", size is " + sectionObject.itemNumber);
|
||||
}
|
||||
if (position + count > sectionObject.itemNumber) {
|
||||
throw new IndexOutOfBoundsException("Invalid index " + (position + count) + ", size is " + sectionObject.itemNumber);
|
||||
}
|
||||
|
||||
notifyItemRangeInserted(sectionObject.position + position + 1, count);
|
||||
}
|
||||
}
|
||||
|
||||
public void notifySectionRemoved(int section) {
|
||||
if (mSections == null) {
|
||||
calculateSections();
|
||||
notifyAllSectionsDataSetChanged();
|
||||
}
|
||||
else {
|
||||
final Section sectionObject = mSections.get(section);
|
||||
calculateSections();
|
||||
notifyItemRangeRemoved(sectionObject.position, sectionObject.length);
|
||||
}
|
||||
}
|
||||
|
||||
public void notifySectionItemRemoved(int section, int position) {
|
||||
if (mSections == null) {
|
||||
calculateSections();
|
||||
notifyAllSectionsDataSetChanged();
|
||||
}
|
||||
else {
|
||||
final Section sectionObject = mSections.get(section);
|
||||
|
||||
if (position < 0 || position >= sectionObject.itemNumber) {
|
||||
throw new IndexOutOfBoundsException("Invalid index " + position + ", size is " + sectionObject.itemNumber);
|
||||
}
|
||||
|
||||
calculateSections();
|
||||
notifyItemRemoved(sectionObject.position + position + 1);
|
||||
}
|
||||
}
|
||||
|
||||
public void notifySectionItemRangeRemoved(int section, int position, int count) {
|
||||
if (mSections == null) {
|
||||
calculateSections();
|
||||
notifyAllSectionsDataSetChanged();
|
||||
}
|
||||
else {
|
||||
final Section sectionObject = mSections.get(section);
|
||||
|
||||
if (position < 0 || position >= sectionObject.itemNumber) {
|
||||
throw new IndexOutOfBoundsException("Invalid index " + position + ", size is " + sectionObject.itemNumber);
|
||||
}
|
||||
if (position + count > sectionObject.itemNumber) {
|
||||
throw new IndexOutOfBoundsException("Invalid index " + (position + count) + ", size is " + sectionObject.itemNumber);
|
||||
}
|
||||
|
||||
calculateSections();
|
||||
notifyItemRangeRemoved(sectionObject.position + position + 1, count);
|
||||
}
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -17,7 +17,6 @@ import java.util.HashSet;
|
||||
import static org.thoughtcrime.securesms.util.MediaUtil.getMimeType;
|
||||
|
||||
import de.cketti.safecontentresolver.SafeContentResolver;
|
||||
import de.cketti.safecontentresolver.SafeContentResolverCompat;
|
||||
|
||||
public class ResolveMediaTask extends AsyncTask<Uri, Void, Uri> {
|
||||
|
||||
@@ -50,7 +49,7 @@ public class ResolveMediaTask extends AsyncTask<Uri, Void, Uri> {
|
||||
String fileName = null;
|
||||
Long fileSize = null;
|
||||
|
||||
SafeContentResolver safeContentResolver = SafeContentResolverCompat.newInstance(contextRef.get());
|
||||
SafeContentResolver safeContentResolver = SafeContentResolver.newInstance(contextRef.get());
|
||||
inputStream = safeContentResolver.openInputStream(uri);
|
||||
|
||||
if (inputStream == null) {
|
||||
|
||||
@@ -16,16 +16,16 @@ import androidx.annotation.Nullable;
|
||||
import com.google.android.exoplayer2.C;
|
||||
import com.google.android.exoplayer2.DefaultLoadControl;
|
||||
import com.google.android.exoplayer2.DefaultRenderersFactory;
|
||||
import com.google.android.exoplayer2.ExoPlaybackException;
|
||||
import com.google.android.exoplayer2.ExoPlayerFactory;
|
||||
import com.google.android.exoplayer2.LoadControl;
|
||||
import com.google.android.exoplayer2.MediaItem;
|
||||
import com.google.android.exoplayer2.PlaybackException;
|
||||
import com.google.android.exoplayer2.Player;
|
||||
import com.google.android.exoplayer2.SimpleExoPlayer;
|
||||
import com.google.android.exoplayer2.audio.AudioAttributes;
|
||||
import com.google.android.exoplayer2.extractor.DefaultExtractorsFactory;
|
||||
import com.google.android.exoplayer2.extractor.ExtractorsFactory;
|
||||
import com.google.android.exoplayer2.source.ExtractorMediaSource;
|
||||
import com.google.android.exoplayer2.source.MediaSource;
|
||||
import com.google.android.exoplayer2.source.ProgressiveMediaSource;
|
||||
import com.google.android.exoplayer2.trackselection.DefaultTrackSelector;
|
||||
import com.google.android.exoplayer2.upstream.DefaultDataSourceFactory;
|
||||
|
||||
@@ -76,10 +76,13 @@ public class AudioSlidePlayer {
|
||||
|
||||
public void requestDuration() {
|
||||
try {
|
||||
LoadControl loadControl = new DefaultLoadControl.Builder().setBufferDurationsMs(Integer.MAX_VALUE, Integer.MAX_VALUE, Integer.MAX_VALUE, Integer.MAX_VALUE).createDefaultLoadControl();
|
||||
durationCalculator = ExoPlayerFactory.newSimpleInstance(context, new DefaultRenderersFactory(context), new DefaultTrackSelector(), loadControl);
|
||||
LoadControl loadControl = new DefaultLoadControl.Builder().setBufferDurationsMs(Integer.MAX_VALUE, Integer.MAX_VALUE, Integer.MAX_VALUE, Integer.MAX_VALUE).build();
|
||||
durationCalculator = new SimpleExoPlayer.Builder(context, new DefaultRenderersFactory(context))
|
||||
.setTrackSelector(new DefaultTrackSelector(context))
|
||||
.setLoadControl(loadControl)
|
||||
.build();
|
||||
durationCalculator.setPlayWhenReady(false);
|
||||
durationCalculator.addListener(new Player.EventListener() {
|
||||
durationCalculator.addListener(new Player.Listener() {
|
||||
@Override
|
||||
public void onPlayerStateChanged(boolean playWhenReady, int playbackState) {
|
||||
if (playbackState == Player.STATE_READY) {
|
||||
@@ -113,16 +116,19 @@ public class AudioSlidePlayer {
|
||||
throw new IOException("Slide has no URI!");
|
||||
}
|
||||
|
||||
LoadControl loadControl = new DefaultLoadControl.Builder().setBufferDurationsMs(Integer.MAX_VALUE, Integer.MAX_VALUE, Integer.MAX_VALUE, Integer.MAX_VALUE).createDefaultLoadControl();
|
||||
this.mediaPlayer = ExoPlayerFactory.newSimpleInstance(context, new DefaultRenderersFactory(context), new DefaultTrackSelector(), loadControl);
|
||||
LoadControl loadControl = new DefaultLoadControl.Builder().setBufferDurationsMs(Integer.MAX_VALUE, Integer.MAX_VALUE, Integer.MAX_VALUE, Integer.MAX_VALUE).build();
|
||||
this.mediaPlayer = new SimpleExoPlayer.Builder(context, new DefaultRenderersFactory(context))
|
||||
.setTrackSelector(new DefaultTrackSelector(context))
|
||||
.setLoadControl(loadControl)
|
||||
.build();
|
||||
|
||||
mediaPlayer.prepare(createMediaSource(slide.getUri()));
|
||||
mediaPlayer.setPlayWhenReady(true);
|
||||
mediaPlayer.setAudioAttributes(new AudioAttributes.Builder()
|
||||
.setContentType(earpiece ? C.CONTENT_TYPE_SPEECH : C.CONTENT_TYPE_MUSIC)
|
||||
.setContentType(earpiece ? C.AUDIO_CONTENT_TYPE_SPEECH : C.AUDIO_CONTENT_TYPE_MUSIC)
|
||||
.setUsage(earpiece ? C.USAGE_VOICE_COMMUNICATION : C.USAGE_MEDIA)
|
||||
.build());
|
||||
mediaPlayer.addListener(new Player.EventListener() {
|
||||
.build(), false);
|
||||
mediaPlayer.addListener(new Player.Listener() {
|
||||
|
||||
boolean started = false;
|
||||
|
||||
@@ -171,7 +177,7 @@ public class AudioSlidePlayer {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPlayerError(ExoPlaybackException error) {
|
||||
public void onPlayerError(PlaybackException error) {
|
||||
Log.w(TAG, "MediaPlayer Error: " + error);
|
||||
|
||||
synchronized (AudioSlidePlayer.this) {
|
||||
@@ -194,9 +200,8 @@ public class AudioSlidePlayer {
|
||||
AttachmentDataSourceFactory attachmentDataSourceFactory = new AttachmentDataSourceFactory(defaultDataSourceFactory);
|
||||
ExtractorsFactory extractorsFactory = new DefaultExtractorsFactory().setConstantBitrateSeekingEnabled(true);
|
||||
|
||||
return new ExtractorMediaSource.Factory(attachmentDataSourceFactory)
|
||||
.setExtractorsFactory(extractorsFactory)
|
||||
.createMediaSource(uri);
|
||||
return new ProgressiveMediaSource.Factory(attachmentDataSourceFactory, extractorsFactory)
|
||||
.createMediaSource(MediaItem.fromUri(uri));
|
||||
}
|
||||
|
||||
public synchronized void stop() {
|
||||
|
||||
@@ -2,6 +2,7 @@ package org.thoughtcrime.securesms.qr;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.os.Bundle;
|
||||
import android.text.TextUtils;
|
||||
import android.util.Log;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
@@ -106,8 +107,11 @@ public class QrScanFragment extends Fragment {
|
||||
// which makes _showing_ the QR-code impossible if scanning goes wrong.
|
||||
// therefore, we only show a non-disturbing error here.
|
||||
@Override
|
||||
protected void displayFrameworkBugMessageAndExit() {
|
||||
Toast.makeText(myActivity, R.string.zxing_msg_camera_framework_bug, Toast.LENGTH_SHORT).show();
|
||||
protected void displayFrameworkBugMessageAndExit(String message) {
|
||||
if (TextUtils.isEmpty(message)) {
|
||||
message = myActivity.getString(R.string.zxing_msg_camera_framework_bug);
|
||||
}
|
||||
Toast.makeText(myActivity, message, Toast.LENGTH_SHORT).show();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -17,27 +17,26 @@
|
||||
package org.thoughtcrime.securesms.video;
|
||||
|
||||
import android.content.Context;
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import android.util.AttributeSet;
|
||||
import android.view.Window;
|
||||
import android.view.WindowManager;
|
||||
import android.widget.FrameLayout;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
import com.google.android.exoplayer2.DefaultLoadControl;
|
||||
import com.google.android.exoplayer2.ExoPlayerFactory;
|
||||
import com.google.android.exoplayer2.LoadControl;
|
||||
import com.google.android.exoplayer2.MediaItem;
|
||||
import com.google.android.exoplayer2.Player;
|
||||
import com.google.android.exoplayer2.SimpleExoPlayer;
|
||||
import com.google.android.exoplayer2.extractor.DefaultExtractorsFactory;
|
||||
import com.google.android.exoplayer2.extractor.ExtractorsFactory;
|
||||
import com.google.android.exoplayer2.source.ExtractorMediaSource;
|
||||
import com.google.android.exoplayer2.source.MediaSource;
|
||||
import com.google.android.exoplayer2.trackselection.AdaptiveTrackSelection;
|
||||
import com.google.android.exoplayer2.source.ProgressiveMediaSource;
|
||||
import com.google.android.exoplayer2.trackselection.DefaultTrackSelector;
|
||||
import com.google.android.exoplayer2.trackselection.TrackSelection;
|
||||
import com.google.android.exoplayer2.trackselection.TrackSelector;
|
||||
import com.google.android.exoplayer2.ui.SimpleExoPlayerView;
|
||||
import com.google.android.exoplayer2.ui.PlayerView;
|
||||
import com.google.android.exoplayer2.upstream.BandwidthMeter;
|
||||
import com.google.android.exoplayer2.upstream.DefaultBandwidthMeter;
|
||||
import com.google.android.exoplayer2.upstream.DefaultDataSourceFactory;
|
||||
@@ -49,7 +48,7 @@ import org.thoughtcrime.securesms.video.exo.AttachmentDataSourceFactory;
|
||||
|
||||
public class VideoPlayer extends FrameLayout {
|
||||
|
||||
@Nullable private final SimpleExoPlayerView exoView;
|
||||
@Nullable private final PlayerView exoView;
|
||||
|
||||
@Nullable private SimpleExoPlayer exoPlayer;
|
||||
@Nullable private Window window;
|
||||
@@ -93,12 +92,15 @@ public class VideoPlayer extends FrameLayout {
|
||||
|
||||
private void setExoViewSource(@NonNull VideoSlide videoSource, boolean autoplay)
|
||||
{
|
||||
BandwidthMeter bandwidthMeter = new DefaultBandwidthMeter();
|
||||
TrackSelection.Factory videoTrackSelectionFactory = new AdaptiveTrackSelection.Factory(bandwidthMeter);
|
||||
TrackSelector trackSelector = new DefaultTrackSelector(videoTrackSelectionFactory);
|
||||
BandwidthMeter bandwidthMeter = new DefaultBandwidthMeter.Builder(getContext()).build();
|
||||
TrackSelector trackSelector = new DefaultTrackSelector(getContext());
|
||||
LoadControl loadControl = new DefaultLoadControl();
|
||||
|
||||
exoPlayer = ExoPlayerFactory.newSimpleInstance(getContext(), trackSelector, loadControl);
|
||||
exoPlayer = new SimpleExoPlayer.Builder(getContext())
|
||||
.setTrackSelector(trackSelector)
|
||||
.setBandwidthMeter(bandwidthMeter)
|
||||
.setLoadControl(loadControl)
|
||||
.build();
|
||||
exoPlayer.addListener(new ExoPlayerListener(window));
|
||||
//noinspection ConstantConditions
|
||||
exoView.setPlayer(exoPlayer);
|
||||
@@ -107,13 +109,14 @@ public class VideoPlayer extends FrameLayout {
|
||||
AttachmentDataSourceFactory attachmentDataSourceFactory = new AttachmentDataSourceFactory(defaultDataSourceFactory);
|
||||
ExtractorsFactory extractorsFactory = new DefaultExtractorsFactory();
|
||||
|
||||
MediaSource mediaSource = new ExtractorMediaSource(videoSource.getUri(), attachmentDataSourceFactory, extractorsFactory, null, null);
|
||||
MediaSource mediaSource = new ProgressiveMediaSource.Factory(attachmentDataSourceFactory, extractorsFactory)
|
||||
.createMediaSource(MediaItem.fromUri(videoSource.getUri()));
|
||||
|
||||
exoPlayer.prepare(mediaSource);
|
||||
exoPlayer.setPlayWhenReady(autoplay);
|
||||
}
|
||||
|
||||
private static class ExoPlayerListener implements Player.EventListener {
|
||||
private static class ExoPlayerListener implements Player.Listener {
|
||||
private final Window window;
|
||||
|
||||
ExoPlayerListener(Window window) {
|
||||
|
||||
@@ -1,14 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:orientation="vertical"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
|
||||
<com.google.android.exoplayer2.ui.SimpleExoPlayerView
|
||||
android:id="@+id/video_view"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_gravity="center"
|
||||
android:gravity="center"/>
|
||||
|
||||
</FrameLayout>
|
||||
@@ -4,10 +4,11 @@
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
|
||||
<VideoView android:id="@+id/video_view"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_gravity="center"
|
||||
android:gravity="center"/>
|
||||
<com.google.android.exoplayer2.ui.PlayerView
|
||||
android:id="@+id/video_view"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_gravity="center"
|
||||
android:gravity="center"/>
|
||||
|
||||
</FrameLayout>
|
||||
</FrameLayout>
|
||||
|
||||
Reference in New Issue
Block a user