diff --git a/app/src/main/java/acr/browser/lightning/activity/BrowserActivity.java b/app/src/main/java/acr/browser/lightning/activity/BrowserActivity.java index 8f63ed7..a32a376 100644 --- a/app/src/main/java/acr/browser/lightning/activity/BrowserActivity.java +++ b/app/src/main/java/acr/browser/lightning/activity/BrowserActivity.java @@ -186,6 +186,8 @@ public abstract class BrowserActivity extends ThemableBrowserActivity implements private String mUntitledTitle; private String mCameraPhotoPath; + private final Handler mDrawerHandler = new Handler(); + // The singleton BookmarkManager @Inject BookmarkManager mBookmarkManager; @@ -923,7 +925,7 @@ public abstract class BrowserActivity extends ThemableBrowserActivity implements // Use a delayed handler to make the transition smooth // otherwise it will get caught up with the showTab code // and cause a janky motion - new Handler().postDelayed(new Runnable() { + mDrawerHandler.postDelayed(new Runnable() { @Override public void run() { mDrawerLayout.closeDrawers(); @@ -959,14 +961,14 @@ public abstract class BrowserActivity extends ThemableBrowserActivity implements // Use a delayed handler to make the transition smooth // otherwise it will get caught up with the showTab code // and cause a janky motion - new Handler().postDelayed(new Runnable() { + mDrawerHandler.postDelayed(new Runnable() { @Override public void run() { mDrawerLayout.closeDrawers(); } }, 200); - // new Handler().postDelayed(new Runnable() { + // mDrawerHandler.postDelayed(new Runnable() { // @Override // public void run() { // Remove browser frame background to reduce overdraw @@ -1168,16 +1170,12 @@ public abstract class BrowserActivity extends ThemableBrowserActivity implements @Override protected void onPause() { super.onPause(); - final LightningView currentTab = mTabsManager.getCurrentTab(); Log.d(TAG, "onPause"); - if (currentTab != null) { - currentTab.pauseTimers(); - currentTab.onPause(); - } + mTabsManager.pauseAll(); try { BrowserApp.get(this).unregisterReceiver(mNetworkReceiver); } catch (IllegalArgumentException e) { - e.printStackTrace(); + Log.e(TAG, "Receiver was not registered", e); } if (isIncognito() && isFinishing()) { overridePendingTransition(R.anim.fade_in_scale, R.anim.slide_down_out); @@ -1227,16 +1225,12 @@ public abstract class BrowserActivity extends ThemableBrowserActivity implements @Override protected void onResume() { super.onResume(); - final LightningView currentTab = mTabsManager.getCurrentTab(); Log.d(TAG, "onResume"); if (mSuggestionsAdapter != null) { mSuggestionsAdapter.refreshPreferences(); mSuggestionsAdapter.refreshBookmarks(); } - if (currentTab != null) { - currentTab.resumeTimers(); - currentTab.onResume(); - } + mTabsManager.resumeAll(); initializePreferences(); mTabsManager.resume(this); @@ -2157,8 +2151,7 @@ public abstract class BrowserActivity extends ThemableBrowserActivity implements mPresenter.loadUrlInCurrentView(event.url); // keep any jank from happening when the drawer is closed after the // URL starts to load - final Handler handler = new Handler(); - handler.postDelayed(new Runnable() { + mDrawerHandler.postDelayed(new Runnable() { @Override public void run() { mDrawerLayout.closeDrawer(mDrawerRight); diff --git a/app/src/main/java/acr/browser/lightning/activity/TabsManager.java b/app/src/main/java/acr/browser/lightning/activity/TabsManager.java index a52e9a8..8efab1d 100644 --- a/app/src/main/java/acr/browser/lightning/activity/TabsManager.java +++ b/app/src/main/java/acr/browser/lightning/activity/TabsManager.java @@ -190,6 +190,44 @@ public class TabsManager { }); } + /** + * Method used to resume all the tabs in the browser. + * This is necessary because we cannot pause the + * WebView when the app is open currently due to a + * bug in the WebView, where calling onResume doesn't + * consistently resume it. + */ + public void resumeAll() { + LightningView current = getCurrentTab(); + if (current != null) { + current.resumeTimers(); + } + for (LightningView tab : mTabList) { + if (tab != null) { + tab.onResume(); + } + } + } + + /** + * Method used to pause all the tabs in the browser. + * This is necessary because we cannot pause the + * WebView when the app is open currently due to a + * bug in the WebView, where calling onResume doesn't + * consistently resume it. + */ + public void pauseAll() { + LightningView current = getCurrentTab(); + if (current != null) { + current.pauseTimers(); + } + for (LightningView tab : mTabList) { + if (tab != null) { + tab.onPause(); + } + } + } + /** * Return the tab at the given position in tabs list, or * null if position is not in tabs list range. diff --git a/app/src/main/java/acr/browser/lightning/app/BrowserApp.java b/app/src/main/java/acr/browser/lightning/app/BrowserApp.java index 8826698..f0689d6 100644 --- a/app/src/main/java/acr/browser/lightning/app/BrowserApp.java +++ b/app/src/main/java/acr/browser/lightning/app/BrowserApp.java @@ -2,7 +2,9 @@ package acr.browser.lightning.app; import android.app.Application; import android.content.Context; +import android.os.Build; import android.support.annotation.NonNull; +import android.webkit.WebView; import com.squareup.leakcanary.LeakCanary; import com.squareup.otto.Bus; @@ -12,6 +14,8 @@ import java.util.concurrent.Executors; import javax.inject.Inject; +import acr.browser.lightning.BuildConfig; + public class BrowserApp extends Application { private static AppComponent mAppComponent; @@ -26,6 +30,9 @@ public class BrowserApp extends Application { mAppComponent = DaggerAppComponent.builder().appModule(new AppModule(this)).build(); mAppComponent.inject(this); LeakCanary.install(this); + if (BuildConfig.DEBUG && Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) { + WebView.setWebContentsDebuggingEnabled(true); + } } @NonNull diff --git a/app/src/main/java/acr/browser/lightning/browser/BrowserPresenter.java b/app/src/main/java/acr/browser/lightning/browser/BrowserPresenter.java index a152818..7b79208 100644 --- a/app/src/main/java/acr/browser/lightning/browser/BrowserPresenter.java +++ b/app/src/main/java/acr/browser/lightning/browser/BrowserPresenter.java @@ -100,12 +100,16 @@ public class BrowserPresenter { } } else { if (mCurrentTab != null) { - mCurrentTab.onPause(); + // TODO: Restore this when Google fixes the bug where the WebView is + // blank after calling onPause followed by onResume. + // mCurrentTab.onPause(); mCurrentTab.setForegroundTab(false); } - newTab.onResume(); + newTab.resumeTimers(); + newTab.onResume(); newTab.setForegroundTab(true); + mView.updateProgress(newTab.getProgress()); mView.setBackButtonEnabled(newTab.canGoBack()); mView.setForwardButtonEnabled(newTab.canGoForward()); @@ -143,6 +147,7 @@ public class BrowserPresenter { * delete the tab. */ public void deleteTab(int position) { + Log.d(TAG, "delete Tab"); final LightningView tabToDelete = mTabsModel.getTabAtPosition(position); if (tabToDelete == null) { @@ -280,6 +285,7 @@ public class BrowserPresenter { * tab to switch to. */ public synchronized void tabChanged(int position) { + Log.d(TAG, "tabChanged: " + position); if (position < 0 || position >= mTabsModel.size()) { return; } diff --git a/app/src/main/java/acr/browser/lightning/react/Observable.java b/app/src/main/java/acr/browser/lightning/react/Observable.java index 1566d64..3605153 100644 --- a/app/src/main/java/acr/browser/lightning/react/Observable.java +++ b/app/src/main/java/acr/browser/lightning/react/Observable.java @@ -143,7 +143,7 @@ public class Observable { private static class SubscriberImpl implements Subscriber { - @Nullable private OnSubscribe mOnSubscribe; + @Nullable private volatile OnSubscribe mOnSubscribe; @NonNull private final Observable mObservable; private boolean mOnCompleteExecuted = false; @@ -159,9 +159,10 @@ public class Observable { @Override public void onComplete() { - if (!mOnCompleteExecuted && mOnSubscribe != null) { + OnSubscribe onSubscribe = mOnSubscribe; + if (!mOnCompleteExecuted && onSubscribe != null) { mOnCompleteExecuted = true; - mObservable.executeOnObserverThread(new OnCompleteRunnable<>(mOnSubscribe)); + mObservable.executeOnObserverThread(new OnCompleteRunnable<>(onSubscribe)); } else { Log.e(TAG, "onComplete called more than once"); throw new RuntimeException("onComplete called more than once"); @@ -170,23 +171,26 @@ public class Observable { @Override public void onStart() { - if (mOnSubscribe != null) { - mObservable.executeOnObserverThread(new OnStartRunnable<>(mOnSubscribe)); + OnSubscribe onSubscribe = mOnSubscribe; + if (onSubscribe != null) { + mObservable.executeOnObserverThread(new OnStartRunnable<>(onSubscribe)); } } @Override public void onError(@NonNull final Throwable throwable) { - if (mOnSubscribe != null) { + OnSubscribe onSubscribe = mOnSubscribe; + if (onSubscribe != null) { mOnCompleteExecuted = true; - mObservable.executeOnObserverThread(new OnErrorRunnable<>(mOnSubscribe, throwable)); + mObservable.executeOnObserverThread(new OnErrorRunnable<>(onSubscribe, throwable)); } } @Override public void onNext(final T item) { - if (!mOnCompleteExecuted && mOnSubscribe != null) { - mObservable.executeOnObserverThread(new OnNextRunnable<>(mOnSubscribe, item)); + OnSubscribe onSubscribe = mOnSubscribe; + if (!mOnCompleteExecuted && onSubscribe != null) { + mObservable.executeOnObserverThread(new OnNextRunnable<>(onSubscribe, item)); } else { Log.e(TAG, "onComplete has been already called, onNext should not be called"); throw new RuntimeException("onNext should not be called after onComplete has been called"); diff --git a/app/src/main/java/acr/browser/lightning/view/LightningView.java b/app/src/main/java/acr/browser/lightning/view/LightningView.java index 9a85687..04c994d 100644 --- a/app/src/main/java/acr/browser/lightning/view/LightningView.java +++ b/app/src/main/java/acr/browser/lightning/view/LightningView.java @@ -77,7 +77,7 @@ public class LightningView { private static String sHomepage; private static String sDefaultUserAgent; - private static float mMaxFling; + private static float sMaxFling; private static final float[] sNegativeColorArray = { -1.0f, 0, 0, 0, 255, // red 0, -1.0f, 0, 0, 255, // green @@ -116,10 +116,13 @@ public class LightningView { mActivity = activity; mUIController = (UIController) activity; mWebView = new WebView(activity); + if (Build.VERSION.SDK_INT > Build.VERSION_CODES.JELLY_BEAN) { + mWebView.setId(View.generateViewId()); + } mIsIncognitoTab = isIncognito; mTitle = new LightningViewTitle(activity); - mMaxFling = ViewConfiguration.get(activity).getScaledMaximumFlingVelocity(); + sMaxFling = ViewConfiguration.get(activity).getScaledMaximumFlingVelocity(); mWebView.setDrawingCacheBackgroundColor(Color.WHITE); mWebView.setFocusableInTouchMode(true); @@ -560,16 +563,20 @@ public class LightningView { * Pause the current WebView instance. */ public synchronized void onPause() { - if (mWebView != null) + if (mWebView != null) { mWebView.onPause(); + Log.d(TAG, "WebView onPause: " + mWebView.getId()); + } } /** * Resume the current WebView instance. */ public synchronized void onResume() { - if (mWebView != null) + if (mWebView != null) { mWebView.onResume(); + Log.d(TAG, "WebView onResume: " + mWebView.getId()); + } } /** @@ -737,17 +744,19 @@ public class LightningView { public synchronized void pauseTimers() { if (mWebView != null) { mWebView.pauseTimers(); + Log.d(TAG, "Pausing JS timers"); } } /** * Resumes the JavaScript timers of the - * WebView instance, whihc will trigger a + * WebView instance, which will trigger a * resume for all WebViews in the app. */ public synchronized void resumeTimers() { if (mWebView != null) { mWebView.resumeTimers(); + Log.d(TAG, "Resuming JS timers"); } } @@ -1122,7 +1131,7 @@ public class LightningView { @Override public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) { - int power = (int) (velocityY * 100 / mMaxFling); + int power = (int) (velocityY * 100 / sMaxFling); if (power < -10) { mUIController.hideActionBar(); } else if (power > 15) {