Skip to content

Commit

Permalink
Add data-saver mode
Browse files Browse the repository at this point in the history
Prevents any images from being loaded from the web. More might follow in
the future.
Also, switches to Glide as the image loading and caching library.

Updates: #265
  • Loading branch information
saemy committed Jan 14, 2019
1 parent 185b634 commit 6fcdaf2
Show file tree
Hide file tree
Showing 16 changed files with 322 additions and 44 deletions.
5 changes: 3 additions & 2 deletions app/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -111,13 +111,13 @@ ext {
butterknifeVersion = '8.8.1'
constraintLayoutVersion = '1.1.2'
daggerVersion = '2.13'
glideVersion = '4.8.0'
gsonVersion = '2.8.1'
jsonVersion = '20170516'
junitVersion = '4.12'
okHttpVersion = '3.12.0'
osmbonuspackVersion = '6.5.2'
osmdroidVersion = '6.0.2'
picassoVersion = '2.5.2'
playServicesVersion = '11.6.2'
retrofitVersion = '2.5.0' // Dictates version of okhttp in their dependencies which clashes in tests.
robolectricVersion = '4.1'
Expand All @@ -127,6 +127,7 @@ ext {
}

dependencies {
annotationProcessor "com.github.bumptech.glide:compiler:$glideVersion"
annotationProcessor "com.google.dagger:dagger-android-processor:$daggerVersion"
annotationProcessor "com.google.dagger:dagger-compiler:$daggerVersion"
annotationProcessor "com.jakewharton:butterknife-compiler:$butterknifeVersion"
Expand All @@ -136,13 +137,13 @@ dependencies {
implementation "com.android.support:design:$supportLibVersion"
implementation "com.android.support:preference-v14:$supportLibVersion"
implementation "com.android.support:support-v4:$supportLibVersion"
implementation "com.github.bumptech.glide:glide:$glideVersion"
implementation "com.github.MKergall:osmbonuspack:$osmbonuspackVersion"
implementation "com.google.code.gson:gson:$gsonVersion"
implementation "com.google.dagger:dagger:$daggerVersion"
implementation "com.google.dagger:dagger-android:$daggerVersion"
implementation "com.google.dagger:dagger-android-support:$daggerVersion"
implementation "com.jakewharton:butterknife:$butterknifeVersion"
implementation "com.squareup.picasso:picasso:$picassoVersion"
implementation "com.squareup.retrofit2:adapter-rxjava2:$retrofitVersion"
implementation "com.squareup.retrofit2:retrofit:$retrofitVersion"
implementation "com.squareup.retrofit2:converter-gson:$retrofitVersion"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,30 +2,45 @@

import android.app.Activity;
import android.app.Application;
import android.content.SharedPreferences;

import com.bumptech.glide.request.RequestOptions;

import javax.inject.Inject;

import dagger.android.DispatchingAndroidInjector;
import dagger.android.HasActivityInjector;
import fi.bitrite.android.ws.di.AppComponent;
import fi.bitrite.android.ws.di.AppInjector;
import fi.bitrite.android.ws.repository.SettingsRepository;
import fi.bitrite.android.ws.util.WSGlide;

public abstract class BaseWSAndroidApplication extends Application implements HasActivityInjector {

public static final String TAG = "WSAndroidApplication";
private static AppInjector mAppInjector;

@Inject DispatchingAndroidInjector<Activity> mDispatchingAndroidInjector;
@Inject SettingsRepository mSettingsRepository;

public static AppComponent getAppComponent() {
return mAppInjector.getAppComponent();
}

@Override
public void onCreate() {
super.onCreate();

mAppInjector = inject();
// Injected variables are available from this point.

mSettingsRepository.registerOnChangeListener(mSettingsChangeListener);
}

@Override
public void onTerminate() {
mSettingsRepository.unregisterOnChangeListener(mSettingsChangeListener);
super.onTerminate();
}

protected abstract AppInjector inject();
Expand All @@ -34,4 +49,12 @@ public void onCreate() {
public DispatchingAndroidInjector<Activity> activityInjector() {
return mDispatchingAndroidInjector;
}

// Ensure that pictures are not loaded in data-saver mode.
private final SharedPreferences.OnSharedPreferenceChangeListener mSettingsChangeListener =
(sharedPreferences, key) -> {
RequestOptions requestOptions = new RequestOptions()
.onlyRetrieveFromCache(mSettingsRepository.isDataSaverMode());
WSGlide.setDefaultRequestOptions(requestOptions);
};
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
import android.content.SharedPreferences;
import android.content.res.Resources;
import android.preference.PreferenceManager;
import android.support.annotation.VisibleForTesting;
import android.text.TextUtils;

import org.osmdroid.tileprovider.tilesource.TileSourceFactory;
Expand All @@ -17,7 +18,8 @@ public enum DistanceUnit {
MILES,
}

final SharedPreferences mSharedPreferences;
@VisibleForTesting(otherwise = VisibleForTesting.PROTECTED)
public final SharedPreferences mSharedPreferences;

private final static String KEY_MAP_LAST_LOCATION = "map_last_location";
private final static String KEYSUFFIX_LOCATION_LATITUDE = "_latitude";
Expand All @@ -28,11 +30,13 @@ public enum DistanceUnit {
private final String mKeyDistanceUnit;
private final String mKeyTileSource;
private final String mKeyMessageRefreshInterval;
private final String mKeyDataSaverMode;
private final String mKeyDevSimulateNoNetwork;

private final String mDefaultDistanceUnit;
private final String mDefaultTileSource = TileSourceFactory.DEFAULT_TILE_SOURCE.name();
private final int mDefaultMessageRefreshInterval;
private final boolean mDefaultDataSaverMode;
private final boolean mDefaultDevSimulateNoNetwork;

private final float mDefaultMapLocationLatitude;
Expand All @@ -53,11 +57,13 @@ public enum DistanceUnit {
mKeyDistanceUnit = res.getString(R.string.prefs_distance_unit_key);
mKeyTileSource = res.getString(R.string.prefs_tile_source_key);
mKeyMessageRefreshInterval = res.getString(R.string.prefs_message_refresh_interval_min_key);
mKeyDataSaverMode = res.getString(R.string.prefs_data_saver_mode_key);
mKeyDevSimulateNoNetwork = res.getString(R.string.prefs_dev_simulate_no_network_key);

mDefaultDistanceUnit = res.getString(R.string.prefs_distance_unit_default);
mDefaultMessageRefreshInterval =
res.getInteger(R.integer.prefs_message_refresh_interval_min_default);
mDefaultDataSaverMode = res.getBoolean(R.bool.prefs_data_saver_mode_default);
mDefaultDevSimulateNoNetwork = res.getBoolean(R.bool.prefs_dev_simulate_no_network_default);

mDefaultMapLocationLatitude =
Expand Down Expand Up @@ -145,6 +151,10 @@ public int getMessageRefreshIntervalMin() {
mKeyMessageRefreshInterval, Integer.toString(mDefaultMessageRefreshInterval)));
}

public boolean isDataSaverMode() {
return mSharedPreferences.getBoolean(mKeyDataSaverMode, mDefaultDataSaverMode);
}

public boolean isDevSimulateNoNetwork() {
return mSharedPreferences.getBoolean(
mKeyDevSimulateNoNetwork, mDefaultDevSimulateNoNetwork);
Expand Down Expand Up @@ -179,6 +189,9 @@ public String getDistanceUnitKey() {
public String getMessageRefreshIntervalKey() {
return mKeyMessageRefreshInterval;
}
public String getDataSaverModeKey() {
return mKeyDataSaverMode;
}
public String getDevSimulateNoNetworkKey() {
return mKeyDevSimulateNoNetwork;
}
Expand Down
7 changes: 5 additions & 2 deletions app/src/main/java/fi/bitrite/android/ws/ui/MainActivity.java
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@
import android.widget.ListView;
import android.widget.TextView;

import com.squareup.picasso.Picasso;
import com.bumptech.glide.request.RequestOptions;

import java.util.Arrays;
import java.util.HashSet;
Expand All @@ -47,6 +47,7 @@
import fi.bitrite.android.ws.ui.util.NavigationController;
import fi.bitrite.android.ws.util.LoggedInUserHelper;
import fi.bitrite.android.ws.util.SerialCompositeDisposable;
import fi.bitrite.android.ws.util.WSGlide;
import io.reactivex.Maybe;
import io.reactivex.MaybeObserver;
import io.reactivex.Observable;
Expand Down Expand Up @@ -444,8 +445,10 @@ private Disposable handleLoggedInUser() {
mImgUserPhoto.setImageResource(
R.drawable.default_userinfo_profile);
} else {
Picasso.with(MainActivity.this)
WSGlide.with(MainActivity.this)
.load(profilePhotoUrl)
.apply(new RequestOptions()
.placeholder(R.drawable.default_userinfo_profile))
.into(mImgUserPhoto); // largeUrl
}
} else {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,9 @@
import android.util.Log;
import android.util.SparseArray;

import com.squareup.picasso.Picasso;
import com.squareup.picasso.Target;
import com.bumptech.glide.request.target.SimpleTarget;
import com.bumptech.glide.request.target.Target;
import com.bumptech.glide.request.transition.Transition;

import java.util.Collections;
import java.util.HashSet;
Expand All @@ -39,6 +40,7 @@
import fi.bitrite.android.ws.repository.UserRepository;
import fi.bitrite.android.ws.ui.listadapter.MessageListAdapter;
import fi.bitrite.android.ws.util.LoggedInUserHelper;
import fi.bitrite.android.ws.util.WSGlide;
import io.reactivex.Observable;
import io.reactivex.android.schedulers.AndroidSchedulers;
import io.reactivex.disposables.CompositeDisposable;
Expand Down Expand Up @@ -135,7 +137,7 @@ private Disposable handleNewThreadList(List<Observable<Resource<MessageThread>>>
})
.map(this::getNotificationEntry)
.flatMap(this::loadParticipantsIntoNotificationEntry)
.observeOn(AndroidSchedulers.mainThread()) // Why is this needed Picasso?
.observeOn(AndroidSchedulers.mainThread())
.flatMap(this::loadPartnerBitmapIntoNotificationEntry)
// .debounce(1, TimeUnit.SECONDS) // Limit number of updates during burst. FIXME: does not deliver all the entries
.subscribe(this::updateNotification, e -> {
Expand Down Expand Up @@ -209,25 +211,23 @@ private Observable<NotificationEntry> loadPartnerBitmapIntoNotificationEntry(

String pictureUrl = partner.profilePicture.getSmallUrl();
if (!TextUtils.isEmpty(pictureUrl)) {
Target target = new Target() {
Target<Bitmap> target = new SimpleTarget<Bitmap>() {
@Override
public void onBitmapLoaded(Bitmap bitmap, Picasso.LoadedFrom from) {
public void onResourceReady(@NonNull Bitmap bitmap,
@Nullable Transition<? super Bitmap> transition) {
entry.partnerProfileBitmap = bitmap;
e.onNext(entry);
}

@Override
public void onBitmapFailed(Drawable errorDrawable) {
public void onLoadFailed(@Nullable Drawable errorDrawable) {
// Ignore the error.
e.onNext(entry);
}

@Override
public void onPrepareLoad(Drawable placeHolderDrawable) {
}
};

Picasso.with(mApplicationContext)
WSGlide.with(mApplicationContext)
.asBitmap()
.load(pictureUrl)
.into(target);
} else {
Expand Down
8 changes: 4 additions & 4 deletions app/src/main/java/fi/bitrite/android/ws/ui/UserFragment.java
Original file line number Diff line number Diff line change
Expand Up @@ -22,14 +22,13 @@
import android.widget.TextView;
import android.widget.Toast;

import com.squareup.picasso.Picasso;
import com.bumptech.glide.request.RequestOptions;

import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.atomic.AtomicInteger;

import javax.inject.Inject;

Expand All @@ -49,6 +48,7 @@
import fi.bitrite.android.ws.util.GlobalInfo;
import fi.bitrite.android.ws.util.ObjectUtils;
import fi.bitrite.android.ws.util.Tools;
import fi.bitrite.android.ws.util.WSGlide;
import io.reactivex.Maybe;
import io.reactivex.android.schedulers.AndroidSchedulers;
import io.reactivex.disposables.Disposable;
Expand Down Expand Up @@ -281,9 +281,9 @@ private void updateUserViewContent() {
// If we're connected and there is a picture, get user picture.
String url = user.profilePicture.getLargeUrl();
if (!TextUtils.isEmpty(url)) {
Picasso.with(getContext())
WSGlide.with(requireContext())
.load(url)
.placeholder(R.drawable.default_userinfo_profile)
.apply(new RequestOptions().placeholder(R.drawable.default_userinfo_profile))
.into(mImgPhoto);
mImgPhoto.setContentDescription(
getString(R.string.content_description_avatar_of_var, user.name));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,21 +2,19 @@


import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.drawable.Drawable;
import android.support.annotation.Nullable;
import android.text.TextUtils;
import android.util.AttributeSet;

import com.squareup.picasso.Picasso;
import com.squareup.picasso.Target;
import com.bumptech.glide.load.resource.drawable.DrawableTransitionOptions;

import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.List;

import fi.bitrite.android.ws.model.SimpleUser;
import fi.bitrite.android.ws.util.WSGlide;

public class UserCircleImageView extends CircleImageView {
private String mUrl;
Expand Down Expand Up @@ -95,29 +93,15 @@ public void setUsers(@Nullable Collection<? extends SimpleUser> users) {
color = colors.get(Math.abs(colorHash) % colors.size());
}

// Cancel any previous calls.
WSGlide.with(getContext()).clear(this);
setImageDrawable(null);
mUrl = url;
if (!TextUtils.isEmpty(url)) {
final String imageUrl = url;
Picasso.with(getContext()).load(url).into(new Target() {
@Override
public void onBitmapLoaded(Bitmap bitmap, Picasso.LoadedFrom from) {
// Check that we are still interested in this image (the user might have changed
// in the meantime).
if (TextUtils.equals(imageUrl, mUrl)) {
setImageBitmap(bitmap);
}
}
@Override
public void onBitmapFailed(Drawable errorDrawable) {
// TODO(saemy): Error handling.
setImageDrawable(errorDrawable);
}
@Override
public void onPrepareLoad(Drawable placeHolderDrawable) {
setImageDrawable(placeHolderDrawable);
}
});
WSGlide.with(getContext())
.load(url)
.transition(DrawableTransitionOptions.withCrossFade())
.into(this);
}
setText(text);
setCircleBackgroundColor(color);
Expand Down
Loading

0 comments on commit 6fcdaf2

Please sign in to comment.