Merge branch '553-pause-periodic-list-refresh-when-view-is-not-visible' into 'master'

Pause Periodic List Refresh when View is not Visible

This MR also sneaks in a second commit which stops the cevron in the forum list to sometimes lose its blue color. I noticed this when testing this MR with short refresh intervals. This is not as nice of specifying the color as a tint, but unfortunately tints are not yet ready for primetime on Android.

Closes #553

See merge request !259
This commit is contained in:
akwizgran
2016-08-01 13:45:00 +00:00
11 changed files with 89 additions and 74 deletions

View File

@@ -1,4 +1,9 @@
<vector android:height="24dp" android:viewportHeight="48.0" <vector xmlns:android="http://schemas.android.com/apk/res/android"
android:viewportWidth="48.0" android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android"> android:width="24dp"
<path android:fillColor="#FF000000" android:pathData="M9.1,19.3l14.9,11.8l14.9,-11.8l-1.9,-2.4l-13,10.4l-13,-10.4z"/> android:height="24dp"
android:viewportHeight="48.0"
android:viewportWidth="48.0">
<path
android:fillColor="#06b9ff"
android:pathData="M9.1,19.3l14.9,11.8l14.9,-11.8l-1.9,-2.4l-13,10.4l-13,-10.4z"/>
</vector> </vector>

View File

@@ -1,4 +1,9 @@
<vector android:height="24dp" android:viewportHeight="48.0" <vector xmlns:android="http://schemas.android.com/apk/res/android"
android:viewportWidth="48.0" android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android"> android:width="24dp"
<path android:fillColor="#FF000000" android:pathData="M38.9,28.7l-14.9,-11.8l-14.9,11.8l1.9,2.4l13,-10.4l13,10.4z"/> android:height="24dp"
android:viewportHeight="48.0"
android:viewportWidth="48.0">
<path
android:fillColor="#06b9ff"
android:pathData="M38.9,28.7l-14.9,-11.8l-14.9,11.8l1.9,2.4l13,-10.4l13,10.4z"/>
</vector> </vector>

View File

@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android"> <selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_selected="true" android:drawable="@drawable/chevron48dp_down"/> <item android:drawable="@drawable/chevron48dp_down" android:state_selected="true"/>
<item android:drawable="@drawable/chevron48dp_up"/> <item android:drawable="@drawable/chevron48dp_up"/>
</selector> </selector>

View File

@@ -148,9 +148,7 @@
android:layout_marginRight="@dimen/margin_medium" android:layout_marginRight="@dimen/margin_medium"
android:layout_marginTop="@dimen/margin_small" android:layout_marginTop="@dimen/margin_small"
android:clickable="true" android:clickable="true"
android:src="@drawable/selector_chevron" android:src="@drawable/selector_chevron"/>
android:tint="@color/briar_button_positive"
/>
<TextView <TextView
android:id="@+id/btn_reply" android:id="@+id/btn_reply"

View File

@@ -153,7 +153,6 @@ public class ContactListFragment extends BaseFragment implements EventListener {
list.setLayoutManager(new LinearLayoutManager(getContext())); list.setLayoutManager(new LinearLayoutManager(getContext()));
list.setAdapter(adapter); list.setAdapter(adapter);
list.setEmptyText(getString(R.string.no_contacts)); list.setEmptyText(getString(R.string.no_contacts));
list.periodicallyUpdateContent();
return contentView; return contentView;
} }
@@ -183,6 +182,7 @@ public class ContactListFragment extends BaseFragment implements EventListener {
super.onResume(); super.onResume();
eventBus.addListener(this); eventBus.addListener(this);
loadContacts(); loadContacts();
list.startPeriodicUpdate();
} }
@Override @Override
@@ -190,6 +190,7 @@ public class ContactListFragment extends BaseFragment implements EventListener {
super.onPause(); super.onPause();
adapter.clear(); adapter.clear();
eventBus.removeListener(this); eventBus.removeListener(this);
list.stopPeriodicUpdate();
} }
private void loadContacts() { private void loadContacts() {

View File

@@ -170,7 +170,6 @@ public class ConversationActivity extends BriarActivity
list.setLayoutManager(new LinearLayoutManager(this)); list.setLayoutManager(new LinearLayoutManager(this));
list.setAdapter(adapter); list.setAdapter(adapter);
list.setEmptyText(getString(R.string.no_private_messages)); list.setEmptyText(getString(R.string.no_private_messages));
list.periodicallyUpdateContent();
content = (EditText) findViewById(R.id.input_text); content = (EditText) findViewById(R.id.input_text);
sendButton = findViewById(R.id.btn_send); sendButton = findViewById(R.id.btn_send);
@@ -205,6 +204,7 @@ public class ConversationActivity extends BriarActivity
notificationManager.blockNotification(groupId); notificationManager.blockNotification(groupId);
notificationManager.clearPrivateMessageNotification(groupId); notificationManager.clearPrivateMessageNotification(groupId);
loadData(); loadData();
list.startPeriodicUpdate();
} }
@Override @Override
@@ -212,6 +212,7 @@ public class ConversationActivity extends BriarActivity
super.onPause(); super.onPause();
eventBus.removeListener(this); eventBus.removeListener(this);
notificationManager.unblockNotification(groupId); notificationManager.unblockNotification(groupId);
list.stopPeriodicUpdate();
if (isFinishing()) markMessagesRead(); if (isFinishing()) markMessagesRead();
} }

View File

@@ -9,7 +9,6 @@ import android.content.Intent;
import android.graphics.drawable.ColorDrawable; import android.graphics.drawable.ColorDrawable;
import android.os.Build; import android.os.Build;
import android.os.Bundle; import android.os.Bundle;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable; import android.support.annotation.Nullable;
import android.support.design.widget.Snackbar; import android.support.design.widget.Snackbar;
import android.support.v4.app.ActivityCompat; import android.support.v4.app.ActivityCompat;
@@ -63,9 +62,9 @@ public class ForumActivity extends BriarActivity implements
ForumController.ForumPostListener { ForumController.ForumPostListener {
static final String FORUM_NAME = "briar.FORUM_NAME"; static final String FORUM_NAME = "briar.FORUM_NAME";
private static final int REQUEST_FORUM_SHARED = 3;
private final static int UNDEFINED = -1; private static final int REQUEST_FORUM_SHARED = 3;
private static final int UNDEFINED = -1;
private static final String KEY_INPUT_VISIBILITY = "inputVisibility"; private static final String KEY_INPUT_VISIBILITY = "inputVisibility";
private static final String KEY_REPLY_ID = "replyId"; private static final String KEY_REPLY_ID = "replyId";
@@ -77,6 +76,9 @@ public class ForumActivity extends BriarActivity implements
@Inject @Inject
protected ForumController forumController; protected ForumController forumController;
// Protected access for testing
protected ForumAdapter forumAdapter;
private BriarRecyclerView recyclerView; private BriarRecyclerView recyclerView;
private EditText textInput; private EditText textInput;
private ViewGroup inputContainer; private ViewGroup inputContainer;
@@ -84,8 +86,6 @@ public class ForumActivity extends BriarActivity implements
private volatile GroupId groupId = null; private volatile GroupId groupId = null;
protected ForumAdapter forumAdapter;
@Override @Override
public void onCreate(final Bundle state) { public void onCreate(final Bundle state) {
super.onCreate(state); super.onCreate(state);
@@ -99,50 +99,46 @@ public class ForumActivity extends BriarActivity implements
String forumName = i.getStringExtra(FORUM_NAME); String forumName = i.getStringExtra(FORUM_NAME);
if (forumName != null) setTitle(forumName); if (forumName != null) setTitle(forumName);
forumAdapter = new ForumAdapter();
inputContainer = (ViewGroup) findViewById(R.id.text_input_container); inputContainer = (ViewGroup) findViewById(R.id.text_input_container);
inputContainer.setVisibility(GONE); inputContainer.setVisibility(GONE);
textInput = (EditText) findViewById(R.id.input_text); textInput = (EditText) findViewById(R.id.input_text);
recyclerView = recyclerView =
(BriarRecyclerView) findViewById(R.id.forum_discussion_list); (BriarRecyclerView) findViewById(R.id.forum_discussion_list);
recyclerView.setAdapter(forumAdapter);
linearLayoutManager = new LinearLayoutManager(this); linearLayoutManager = new LinearLayoutManager(this);
recyclerView.setLayoutManager(linearLayoutManager); recyclerView.setLayoutManager(linearLayoutManager);
recyclerView.setEmptyText(getString(R.string.no_forum_posts)); recyclerView.setEmptyText(getString(R.string.no_forum_posts));
recyclerView.showProgressBar(); recyclerView.showProgressBar();
forumController.loadForum(groupId, forumController.loadForum(groupId, new UiResultHandler<Boolean>(this) {
new UiResultHandler<Boolean>(this) { @Override
@Override public void onResultUi(Boolean result) {
public void onResultUi(Boolean result) { if (result) {
if (result) { Forum forum = forumController.getForum();
Forum forum = forumController.getForum(); if (forum != null) setTitle(forum.getName());
if (forum != null) setTitle(forum.getName()); forumAdapter.setEntries(forumController.getForumEntries());
forumAdapter = new ForumAdapter( if (state != null) {
forumController.getForumEntries()); byte[] replyId = state.getByteArray(KEY_REPLY_ID);
recyclerView.setAdapter(forumAdapter); if (replyId != null)
recyclerView.periodicallyUpdateContent(); forumAdapter.setReplyEntryById(replyId);
if (state != null) {
byte[] replyId =
state.getByteArray(KEY_REPLY_ID);
if (replyId != null) {
forumAdapter.setReplyEntryById(replyId);
}
}
recyclerView.showData();
} else {
// TODO Maybe an error dialog ?
finish();
}
} }
}); recyclerView.showData();
} else {
// TODO Maybe an error dialog ?
finish();
}
}
});
} }
@Override @Override
protected void onRestoreInstanceState(Bundle savedInstanceState) { protected void onRestoreInstanceState(Bundle savedInstanceState) {
super.onRestoreInstanceState(savedInstanceState); super.onRestoreInstanceState(savedInstanceState);
inputContainer inputContainer.setVisibility(
.setVisibility( savedInstanceState.getBoolean(KEY_INPUT_VISIBILITY) ?
savedInstanceState.getBoolean(KEY_INPUT_VISIBILITY) ? VISIBLE : GONE);
VISIBLE : GONE);
} }
@@ -250,12 +246,14 @@ public class ForumActivity extends BriarActivity implements
super.onResume(); super.onResume();
notificationManager.blockNotification(groupId); notificationManager.blockNotification(groupId);
notificationManager.clearForumPostNotification(groupId); notificationManager.clearForumPostNotification(groupId);
recyclerView.startPeriodicUpdate();
} }
@Override @Override
public void onPause() { public void onPause() {
super.onPause(); super.onPause();
notificationManager.unblockNotification(groupId); notificationManager.unblockNotification(groupId);
recyclerView.stopPeriodicUpdate();
} }
public void sendMessage(View view) { public void sendMessage(View view) {
@@ -367,23 +365,25 @@ public class ForumActivity extends BriarActivity implements
public class ForumAdapter extends RecyclerView.Adapter<ForumViewHolder> { public class ForumAdapter extends RecyclerView.Adapter<ForumViewHolder> {
private final List<ForumEntry> forumEntries; private final List<ForumEntry> forumEntries = new ArrayList<>();
private final Map<ForumEntry, ValueAnimator> animatingEntries =
new HashMap<>();
// highlight not dependant on time // highlight not dependant on time
private ForumEntry replyEntry; private ForumEntry replyEntry;
// temporary highlight // temporary highlight
private ForumEntry addedEntry; private ForumEntry addedEntry;
Map<ForumEntry, ValueAnimator> animatingEntries = new HashMap<>();
ForumAdapter(@NonNull List<ForumEntry> forumEntries) {
this.forumEntries = forumEntries;
}
private ForumEntry getReplyEntry() { private ForumEntry getReplyEntry() {
return replyEntry; return replyEntry;
} }
void addEntry(int index, ForumEntry entry, void setEntries(List<ForumEntry> entries) {
boolean isScrolling) { forumEntries.clear();
forumEntries.addAll(entries);
}
void addEntry(int index, ForumEntry entry, boolean isScrolling) {
forumEntries.add(index, entry); forumEntries.add(index, entry);
boolean isShowingDescendants = false; boolean isShowingDescendants = false;
if (entry.getLevel() > 0) { if (entry.getLevel() > 0) {
@@ -553,7 +553,7 @@ public class ForumActivity extends BriarActivity implements
return null; return null;
} }
@TargetApi(Build.VERSION_CODES.HONEYCOMB) @TargetApi(11)
private void animateFadeOut(final ForumViewHolder ui, private void animateFadeOut(final ForumViewHolder ui,
final ForumEntry addedEntry) { final ForumEntry addedEntry) {
ui.setIsRecyclable(false); ui.setIsRecyclable(false);
@@ -599,8 +599,8 @@ public class ForumActivity extends BriarActivity implements
} }
@Override @Override
public ForumViewHolder onCreateViewHolder( public ForumViewHolder onCreateViewHolder(ViewGroup parent,
ViewGroup parent, int viewType) { int viewType) {
View v = LayoutInflater.from(parent.getContext()) View v = LayoutInflater.from(parent.getContext())
.inflate(R.layout.forum_discussion_cell, parent, false); .inflate(R.layout.forum_discussion_cell, parent, false);
return new ForumViewHolder(v); return new ForumViewHolder(v);
@@ -724,5 +724,4 @@ public class ForumActivity extends BriarActivity implements
} }
} }
} }

View File

@@ -84,7 +84,6 @@ public class ForumListFragment extends BaseEventFragment implements
list.setLayoutManager(new LinearLayoutManager(getActivity())); list.setLayoutManager(new LinearLayoutManager(getActivity()));
list.setAdapter(adapter); list.setAdapter(adapter);
list.setEmptyText(getString(R.string.no_forums)); list.setEmptyText(getString(R.string.no_forums));
list.periodicallyUpdateContent();
snackbar = Snackbar.make(list, "", LENGTH_INDEFINITE); snackbar = Snackbar.make(list, "", LENGTH_INDEFINITE);
snackbar.getView().setBackgroundResource(R.color.briar_primary); snackbar.getView().setBackgroundResource(R.color.briar_primary);
@@ -111,6 +110,7 @@ public class ForumListFragment extends BaseEventFragment implements
loadForumHeaders(); loadForumHeaders();
loadAvailableForums(); loadAvailableForums();
list.startPeriodicUpdate();
} }
@Override @Override
@@ -118,6 +118,7 @@ public class ForumListFragment extends BaseEventFragment implements
super.onPause(); super.onPause();
adapter.clear(); adapter.clear();
list.stopPeriodicUpdate();
} }
@Override @Override

View File

@@ -30,6 +30,8 @@ import static android.text.format.DateUtils.WEEK_IN_MILLIS;
public class AndroidUtils { public class AndroidUtils {
static final long MIN_RESOLUTION = MINUTE_IN_MILLIS;
// Fake Bluetooth address returned by BluetoothAdapter on API 23 and later // Fake Bluetooth address returned by BluetoothAdapter on API 23 and later
private static final String FAKE_BLUETOOTH_ADDRESS = "02:00:00:00:00:00"; private static final String FAKE_BLUETOOTH_ADDRESS = "02:00:00:00:00:00";
@@ -97,22 +99,20 @@ public class AndroidUtils {
} }
public static String formatDate(Context ctx, long time) { public static String formatDate(Context ctx, long time) {
// update BriarRecyclerView#DEFAULT_REFRESH_INTERVAL along with this
long minResolution = MINUTE_IN_MILLIS;
int flags = FORMAT_ABBREV_RELATIVE | int flags = FORMAT_ABBREV_RELATIVE |
FORMAT_SHOW_DATE | FORMAT_ABBREV_TIME | FORMAT_ABBREV_MONTH; FORMAT_SHOW_DATE | FORMAT_ABBREV_TIME | FORMAT_ABBREV_MONTH;
long diff = System.currentTimeMillis() - time; long diff = System.currentTimeMillis() - time;
if (diff < minResolution) return ctx.getString(R.string.now); if (diff < MIN_RESOLUTION) return ctx.getString(R.string.now);
if (diff >= DAY_IN_MILLIS && diff < WEEK_IN_MILLIS) { if (diff >= DAY_IN_MILLIS && diff < WEEK_IN_MILLIS) {
// also show time when older than a day, but newer than a week // also show time when older than a day, but newer than a week
return DateUtils.getRelativeDateTimeString(ctx, time, minResolution, return DateUtils.getRelativeDateTimeString(ctx, time,
WEEK_IN_MILLIS, flags).toString(); MIN_RESOLUTION, WEEK_IN_MILLIS, flags).toString();
} }
// otherwise just show "...ago" or date string // otherwise just show "...ago" or date string
return DateUtils return DateUtils
.getRelativeTimeSpanString(time, System.currentTimeMillis(), .getRelativeTimeSpanString(time, System.currentTimeMillis(),
minResolution, flags).toString(); MIN_RESOLUTION, flags).toString();
} }
} }

View File

@@ -16,10 +16,14 @@ import org.briarproject.R;
import java.util.logging.Logger; import java.util.logging.Logger;
import static android.text.format.DateUtils.MINUTE_IN_MILLIS; import static org.briarproject.android.util.AndroidUtils.MIN_RESOLUTION;
public class BriarRecyclerView extends FrameLayout { public class BriarRecyclerView extends FrameLayout {
private static final long DEFAULT_REFRESH_INTERVAL = MIN_RESOLUTION;
private static final Logger LOG =
Logger.getLogger(BriarRecyclerView.class.getName());
private RecyclerView recyclerView; private RecyclerView recyclerView;
private TextView emptyView; private TextView emptyView;
private ProgressBar progressBar; private ProgressBar progressBar;
@@ -27,9 +31,6 @@ public class BriarRecyclerView extends FrameLayout {
private Runnable refresher = null; private Runnable refresher = null;
private boolean isScrollingToEnd = false; private boolean isScrollingToEnd = false;
private final Logger LOG = Logger.getLogger(getClass().getName());
private final long DEFAULT_REFRESH_INTERVAL = MINUTE_IN_MILLIS;
public BriarRecyclerView(Context context) { public BriarRecyclerView(Context context) {
this(context, null, 0); this(context, null, 0);
} }
@@ -52,10 +53,7 @@ public class BriarRecyclerView extends FrameLayout {
@Override @Override
protected void onDetachedFromWindow() { protected void onDetachedFromWindow() {
super.onDetachedFromWindow(); super.onDetachedFromWindow();
if (refresher != null) { stopPeriodicUpdate();
LOG.info("Removing Handler Callback");
removeCallbacks(refresher);
}
} }
private void initViews() { private void initViews() {
@@ -172,7 +170,7 @@ public class BriarRecyclerView extends FrameLayout {
return this.recyclerView; return this.recyclerView;
} }
public void periodicallyUpdateContent() { public void startPeriodicUpdate() {
if (recyclerView == null || recyclerView.getAdapter() == null) { if (recyclerView == null || recyclerView.getAdapter() == null) {
throw new IllegalStateException("Need to call setAdapter() first!"); throw new IllegalStateException("Need to call setAdapter() first!");
} }
@@ -188,4 +186,11 @@ public class BriarRecyclerView extends FrameLayout {
postDelayed(refresher, DEFAULT_REFRESH_INTERVAL); postDelayed(refresher, DEFAULT_REFRESH_INTERVAL);
} }
public void stopPeriodicUpdate() {
if (refresher != null) {
LOG.info("Removing Handler Callback");
removeCallbacks(refresher);
}
}
} }

View File

@@ -9,7 +9,7 @@ import org.briarproject.android.forum.ForumControllerImpl;
import org.mockito.Mockito; import org.mockito.Mockito;
/** /**
* This class exposes the SetupController and offers the possibility to * This class exposes the ForumController and offers the possibility to
* override it. * override it.
*/ */
public class TestForumActivity extends ForumActivity { public class TestForumActivity extends ForumActivity {