Commit be6ff749 authored by David Maunder's avatar David Maunder Committed by Commit Bot

Add TabContextObserver

TabContextObserver is used to signal changes to the tab model.
It has applications where we want to prefetch the tab close
suggestions after the tab model changes so they are available
for the UI thread (and the UI thread doesn't have to block on them).

Bug: 1005573
Change-Id: I91ea9367a90301d6bc6dc9a00c141c59a574db5a
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1811935
Commit-Queue: David Maunder <davidjm@chromium.org>
Reviewed-by: default avatarYusuf Ozuysal <yusufo@chromium.org>
Cr-Commit-Position: refs/heads/master@{#700294}
parent 816c828f
...@@ -136,6 +136,7 @@ android_library("java") { ...@@ -136,6 +136,7 @@ android_library("java") {
"java/src/org/chromium/chrome/browser/tasks/tab_management/UndoGroupSnackbarController.java", "java/src/org/chromium/chrome/browser/tasks/tab_management/UndoGroupSnackbarController.java",
"java/src/org/chromium/chrome/browser/tasks/tab_management/suggestions/TabSuggestionProvider.java", "java/src/org/chromium/chrome/browser/tasks/tab_management/suggestions/TabSuggestionProvider.java",
"java/src/org/chromium/chrome/browser/tasks/tab_management/suggestions/StaleTabSuggestionProvider.java", "java/src/org/chromium/chrome/browser/tasks/tab_management/suggestions/StaleTabSuggestionProvider.java",
"java/src/org/chromium/chrome/browser/tasks/tab_management/suggestions/TabContextObserver.java",
"java/src/org/chromium/chrome/browser/tasks/tab_management/suggestions/TabSuggestionsRanker.java", "java/src/org/chromium/chrome/browser/tasks/tab_management/suggestions/TabSuggestionsRanker.java",
"java/src/org/chromium/chrome/browser/tasks/tab_management/suggestions/TabSuggestionProviderConfiguration.java", "java/src/org/chromium/chrome/browser/tasks/tab_management/suggestions/TabSuggestionProviderConfiguration.java",
] ]
......
// Copyright 2019 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
package org.chromium.chrome.browser.tasks.tab_management.suggestions;
import org.chromium.chrome.browser.tab.Tab;
import org.chromium.chrome.browser.tabmodel.EmptyTabModelObserver;
import org.chromium.chrome.browser.tabmodel.TabModelObserver;
import org.chromium.chrome.browser.tabmodel.TabModelSelector;
import org.chromium.chrome.browser.tabmodel.TabModelSelectorTabObserver;
/**
* Monitors changes to a TabContext and executes a callback function if there are changes.
*/
public abstract class TabContextObserver {
protected TabModelSelectorTabObserver mTabModelSelectorTabObserver;
protected TabModelObserver mTabModelObserver;
protected TabModelSelector mTabModelSelector;
/**
* Creates an instance of a {@link TabContextObserver}.
*
* @param selector a tab model selector
*/
public TabContextObserver(TabModelSelector selector) {
mTabModelSelectorTabObserver = new TabModelSelectorTabObserver(selector) {
@Override
public void didFirstVisuallyNonEmptyPaint(Tab tab) {
onTabContextChanged(TabContextChangeReason.FIRST_VISUALLY_NON_EMPTY_PAINT);
}
};
mTabModelObserver = new EmptyTabModelObserver() {
@Override
public void didAddTab(Tab tab, int type) {
onTabContextChanged(TabContextChangeReason.TAB_ADDED);
}
@Override
public void didMoveTab(Tab tab, int newIndex, int curIndex) {
onTabContextChanged(TabContextChangeReason.TAB_MOVED);
}
@Override
public void didCloseTab(int tabId, boolean incognito) {
onTabContextChanged(TabContextChangeReason.TAB_CLOSED);
}
};
selector.getTabModelFilterProvider().addTabModelFilterObserver(mTabModelObserver);
mTabModelSelector = selector;
}
public void destroy() {
mTabModelSelector.getTabModelFilterProvider().removeTabModelFilterObserver(
mTabModelObserver);
mTabModelSelectorTabObserver.destroy();
}
public @interface TabContextChangeReason {
int TAB_MOVED = 0;
int TAB_ADDED = 1;
int TAB_CLOSED = 2;
int FIRST_VISUALLY_NON_EMPTY_PAINT = 3;
}
/**
* Executes when the tab model changes
* @param changeReason the reason the TabContext changes
*/
public abstract void onTabContextChanged(@TabContextChangeReason int changeReason);
}
// Copyright 2019 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
package org.chromium.chrome.browser.tasks.tab_management.suggestions;
import static org.mockito.Mockito.any;
import static org.mockito.Mockito.doNothing;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.TestRule;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.robolectric.annotation.Config;
import org.chromium.chrome.browser.tabmodel.TabModelFilterProvider;
import org.chromium.chrome.browser.tabmodel.TabModelObserver;
import org.chromium.chrome.browser.tabmodel.TabModelSelector;
import org.chromium.chrome.browser.tabmodel.TabModelSelectorTabObserver;
import org.chromium.chrome.test.util.browser.Features;
import org.chromium.testing.local.LocalRobolectricTestRunner;
/**
* Tests for TabContextObserver
*/
@RunWith(LocalRobolectricTestRunner.class)
@Config(manifest = Config.NONE)
public class TabContextObserverTest {
@Rule
public TestRule mProcessor = new Features.JUnitProcessor();
@Mock
private TabModelSelector mTabModelSelector;
@Mock
private TabModelFilterProvider mTabModelFitlerProvider;
@Mock
private TabModelSelectorTabObserver mTabModelSelectorTabObserver;
static class TabContextObserverTestHelper extends TabContextObserver {
private int mChangeReason;
public TabContextObserverTestHelper(TabModelSelector selector) {
super(selector);
}
@Override
public void onTabContextChanged(@TabContextChangeReason int changeReason) {
mChangeReason = changeReason;
}
public int getChangeReason() {
return mChangeReason;
}
}
@Before
public void setUp() throws Exception {
MockitoAnnotations.initMocks(this);
doReturn(mTabModelFitlerProvider).when(mTabModelSelector).getTabModelFilterProvider();
doNothing()
.when(mTabModelFitlerProvider)
.addTabModelFilterObserver(any(TabModelObserver.class));
doNothing().when(mTabModelSelectorTabObserver).destroy();
}
@Test
public void testAddTab() throws Exception {
TabContextObserverTestHelper tabContextObserverTestHelper =
new TabContextObserverTestHelper(mTabModelSelector);
tabContextObserverTestHelper.mTabModelObserver.didAddTab(null, 0);
Assert.assertEquals(TabContextObserver.TabContextChangeReason.TAB_ADDED,
tabContextObserverTestHelper.getChangeReason());
}
@Test
public void testMoveTab() throws Exception {
TabContextObserverTestHelper tabContextObserverTestHelper =
new TabContextObserverTestHelper(mTabModelSelector);
tabContextObserverTestHelper.mTabModelObserver.didMoveTab(null, 0, 0);
Assert.assertEquals(TabContextObserver.TabContextChangeReason.TAB_MOVED,
tabContextObserverTestHelper.getChangeReason());
}
@Test
public void testCloseTab() throws Exception {
TabContextObserverTestHelper tabContextObserverTestHelper =
new TabContextObserverTestHelper(mTabModelSelector);
tabContextObserverTestHelper.mTabModelObserver.didCloseTab(0, false);
Assert.assertEquals(TabContextObserver.TabContextChangeReason.TAB_CLOSED,
tabContextObserverTestHelper.getChangeReason());
}
@Test
public void testDidFirstVisuallyNonEmptyPaint() throws Exception {
TabContextObserverTestHelper tabContextObserverTestHelper =
new TabContextObserverTestHelper(mTabModelSelector);
tabContextObserverTestHelper.mTabModelSelectorTabObserver.didFirstVisuallyNonEmptyPaint(
null);
Assert.assertEquals(
TabContextObserver.TabContextChangeReason.FIRST_VISUALLY_NON_EMPTY_PAINT,
tabContextObserverTestHelper.getChangeReason());
}
@Test
public void testDestroy() throws Exception {
TabContextObserverTestHelper tabContextObserverTestHelper =
new TabContextObserverTestHelper(mTabModelSelector);
tabContextObserverTestHelper.mTabModelSelectorTabObserver = mTabModelSelectorTabObserver;
tabContextObserverTestHelper.destroy();
verify(mTabModelSelectorTabObserver, times(1)).destroy();
}
}
...@@ -40,5 +40,6 @@ tab_management_junit_java_sources = [ ...@@ -40,5 +40,6 @@ tab_management_junit_java_sources = [
"//chrome/android/features/tab_ui/junit/src/org/chromium/chrome/browser/tasks/tab_management/TabGroupUiMediatorUnitTest.java", "//chrome/android/features/tab_ui/junit/src/org/chromium/chrome/browser/tasks/tab_management/TabGroupUiMediatorUnitTest.java",
"//chrome/android/features/tab_ui/junit/src/org/chromium/chrome/browser/tasks/tab_management/TabListMediatorUnitTest.java", "//chrome/android/features/tab_ui/junit/src/org/chromium/chrome/browser/tasks/tab_management/TabListMediatorUnitTest.java",
"//chrome/android/features/tab_ui/junit/src/org/chromium/chrome/browser/tasks/tab_management/suggestions/TabContextTests.java", "//chrome/android/features/tab_ui/junit/src/org/chromium/chrome/browser/tasks/tab_management/suggestions/TabContextTests.java",
"//chrome/android/features/tab_ui/junit/src/org/chromium/chrome/browser/tasks/tab_management/suggestions/TabContextObserverTest.java",
"//chrome/android/features/tab_ui/junit/src/org/chromium/chrome/browser/tasks/tab_management/suggestions/StaleTabSuggestionProviderTest.java", "//chrome/android/features/tab_ui/junit/src/org/chromium/chrome/browser/tasks/tab_management/suggestions/StaleTabSuggestionProviderTest.java",
] ]
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment