-
Notifications
You must be signed in to change notification settings - Fork 615
Use manual foreground detection to trigger network reconnect #2763
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 5 commits
f3a5738
98a7ba7
63cf21a
3907fed
9b0cebd
d9051b6
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -17,27 +17,35 @@ | |
import static com.google.firebase.firestore.util.Assert.hardAssert; | ||
|
||
import android.annotation.TargetApi; | ||
import android.app.Activity; | ||
import android.app.Application; | ||
import android.content.BroadcastReceiver; | ||
import android.content.ComponentCallbacks2; | ||
import android.content.Context; | ||
import android.content.Intent; | ||
import android.content.IntentFilter; | ||
import android.content.res.Configuration; | ||
import android.net.ConnectivityManager; | ||
import android.net.Network; | ||
import android.os.Build; | ||
import android.os.Bundle; | ||
import androidx.annotation.NonNull; | ||
import androidx.annotation.Nullable; | ||
import com.google.android.gms.common.api.internal.BackgroundDetector; | ||
import com.google.firebase.firestore.util.Consumer; | ||
import com.google.firebase.firestore.util.Logger; | ||
import java.util.ArrayList; | ||
import java.util.List; | ||
import java.util.concurrent.atomic.AtomicBoolean; | ||
|
||
/** | ||
* Android implementation of ConnectivityMonitor. Parallel implementations exist for N+ and pre-N. | ||
* | ||
* <p>Implementation note: Most of the code here was shamelessly stolen from | ||
* https://github.com/grpc/grpc-java/blob/master/android/src/main/java/io/grpc/android/AndroidChannelBuilder.java | ||
*/ | ||
public final class AndroidConnectivityMonitor | ||
implements ConnectivityMonitor, BackgroundDetector.BackgroundStateChangeListener { | ||
public final class AndroidConnectivityMonitor implements ConnectivityMonitor { | ||
|
||
private static final String LOG_TAG = "AndroidConnectivityMonitor"; | ||
|
||
private final Context context; | ||
@Nullable private final ConnectivityManager connectivityManager; | ||
|
@@ -78,34 +86,72 @@ private void configureNetworkMonitoring() { | |
final DefaultNetworkCallback defaultNetworkCallback = new DefaultNetworkCallback(); | ||
connectivityManager.registerDefaultNetworkCallback(defaultNetworkCallback); | ||
unregisterRunnable = | ||
new Runnable() { | ||
@Override | ||
public void run() { | ||
connectivityManager.unregisterNetworkCallback(defaultNetworkCallback); | ||
} | ||
}; | ||
() -> connectivityManager.unregisterNetworkCallback(defaultNetworkCallback); | ||
} else { | ||
NetworkReceiver networkReceiver = new NetworkReceiver(); | ||
@SuppressWarnings("deprecation") | ||
IntentFilter networkIntentFilter = new IntentFilter(ConnectivityManager.CONNECTIVITY_ACTION); | ||
context.registerReceiver(networkReceiver, networkIntentFilter); | ||
unregisterRunnable = | ||
new Runnable() { | ||
@Override | ||
public void run() { | ||
context.unregisterReceiver(networkReceiver); | ||
} | ||
}; | ||
unregisterRunnable = () -> context.unregisterReceiver(networkReceiver); | ||
} | ||
} | ||
|
||
private void configureBackgroundStateListener() { | ||
BackgroundDetector.getInstance().addListener(this); | ||
Application applicationContext = (Application) context.getApplicationContext(); | ||
final AtomicBoolean inBackground = new AtomicBoolean(); | ||
|
||
// Manually register an ActivityLifecycleCallback. Android's BackgroundDetector only notifies | ||
// when it is certain that the app transitioned from background to foreground. Instead, we | ||
// want to be notified whenever there is a slight chance that this transition happened. | ||
applicationContext.registerActivityLifecycleCallbacks( | ||
new Application.ActivityLifecycleCallbacks() { | ||
@Override | ||
public void onActivityCreated(@NonNull Activity activity, Bundle savedInstanceState) {} | ||
|
||
@Override | ||
public void onActivityStarted(@NonNull Activity activity) {} | ||
|
||
@Override | ||
public void onActivityResumed(@NonNull Activity activity) { | ||
if (inBackground.compareAndSet(true, false)) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Consider putting the body of There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. That's a good idea. It might not make a huge difference in practice since bringing up the network is a pretty heavy operation on its own, but it certainly should not hut (at least I would hope so). |
||
raiseForegroundNotification(); | ||
} | ||
} | ||
|
||
@Override | ||
public void onActivityPaused(@NonNull Activity activity) {} | ||
|
||
@Override | ||
public void onActivityStopped(@NonNull Activity activity) {} | ||
|
||
@Override | ||
public void onActivitySaveInstanceState( | ||
@NonNull Activity activity, @NonNull Bundle outState) {} | ||
|
||
@Override | ||
public void onActivityDestroyed(@NonNull Activity activity) {} | ||
}); | ||
|
||
applicationContext.registerComponentCallbacks( | ||
new ComponentCallbacks2() { | ||
@Override | ||
public void onTrimMemory(int level) { | ||
if (level == ComponentCallbacks2.TRIM_MEMORY_UI_HIDDEN) { | ||
inBackground.set(true); | ||
} | ||
} | ||
|
||
@Override | ||
public void onConfigurationChanged(@NonNull Configuration newConfig) {} | ||
|
||
@Override | ||
public void onLowMemory() {} | ||
}); | ||
} | ||
|
||
@Override | ||
public void onBackgroundStateChanged(boolean background) { | ||
if (!background && isConnected()) { | ||
public void raiseForegroundNotification() { | ||
Logger.debug(LOG_TAG, "App has entered the foreground."); | ||
if (isConnected()) { | ||
raiseCallbacks(/* connected= */ true); | ||
} | ||
} | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit:
applicationContext
can be renamed toapplication
since it is being casted to an instance ofApplication
.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done