diff --git a/DEPS b/DEPS index ea70baa..ccb3929 100644 --- a/DEPS +++ b/DEPS
@@ -40,11 +40,11 @@ # Three lines of non-changing comments so that # the commit queue can handle CLs rolling Skia # and whatever else without interference from each other. - 'skia_revision': '9018952290a468886c819405c6d9495b4aa5d7d4', + 'skia_revision': '78c8f30d6167b4bf40937c6a8814cd448e2228a6', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling V8 # and whatever else without interference from each other. - 'v8_revision': '309a9310a4b080f4cb216ff9c7aaab71869487ad', + 'v8_revision': '942ddf2c38ef250d149e83cc2fdb53964dc06c0b', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling swarming_client # and whatever else without interference from each other. @@ -64,7 +64,7 @@ # Three lines of non-changing comments so that # the commit queue can handle CLs rolling PDFium # and whatever else without interference from each other. - 'pdfium_revision': 'ef73cf5838ab3a902872d9fc57a90621cc3d7f21', + 'pdfium_revision': 'dc3a87c88da1ac710eadabeb2e5cf01aecb63f4b', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling openmax_dl # and whatever else without interference from each other. @@ -96,7 +96,7 @@ # Three lines of non-changing comments so that # the commit queue can handle CLs rolling catapult # and whatever else without interference from each other. - 'catapult_revision': '37015fb470d81b7a96a091127590e6e461705059', + 'catapult_revision': '9e7bc18ce70595be32d8534b4309aff83ac78434', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling libFuzzer # and whatever else without interference from each other. @@ -196,7 +196,7 @@ Var('chromium_git') + '/external/bidichecker/lib.git' + '@' + '97f2aa645b74c28c57eca56992235c79850fa9e0', 'src/third_party/webgl/src': - Var('chromium_git') + '/external/khronosgroup/webgl.git' + '@' + '6517159d2016833417582d46a8dfc4e941ac0bd2', + Var('chromium_git') + '/external/khronosgroup/webgl.git' + '@' + '87aaf44c5333e8b209baf5e11baa325b79ddeb62', 'src/third_party/webdriver/pylib': Var('chromium_git') + '/external/selenium/py.git' + '@' + '5fd78261a75fe08d27ca4835fb6c5ce4b42275bd', @@ -232,7 +232,7 @@ Var('chromium_git') + '/native_client/src/third_party/scons-2.0.1.git' + '@' + '1c1550e17fc26355d08627fbdec13d8291227067', 'src/third_party/webrtc': - Var('chromium_git') + '/external/webrtc/trunk/webrtc.git' + '@' + '9d4241cbf21ab48686b80918bf5e4d72f2c15574', # commit position 18140 + Var('chromium_git') + '/external/webrtc/trunk/webrtc.git' + '@' + 'a24bcceea4a66fb3201255809f369b765083004f', # commit position 18147 'src/third_party/openmax_dl': Var('chromium_git') + '/external/webrtc/deps/third_party/openmax.git' + '@' + Var('openmax_dl_revision'), @@ -403,7 +403,7 @@ # For Linux and Chromium OS. 'src/third_party/cros_system_api': - Var('chromium_git') + '/chromiumos/platform/system_api.git' + '@' + '2a19709e6f2e52d8e8e276b63e46a0ff31020d57', + Var('chromium_git') + '/chromiumos/platform/system_api.git' + '@' + '6b09df23f8a968fc72956218a62302b89d5334b1', # Build tools for Chrome OS. Note: This depends on third_party/pyelftools. 'src/third_party/chromite':
diff --git a/android_webview/javatests/src/org/chromium/android_webview/test/AwContentsTest.java b/android_webview/javatests/src/org/chromium/android_webview/test/AwContentsTest.java index 29e96a87..0350cf6 100644 --- a/android_webview/javatests/src/org/chromium/android_webview/test/AwContentsTest.java +++ b/android_webview/javatests/src/org/chromium/android_webview/test/AwContentsTest.java
@@ -32,8 +32,8 @@ import org.chromium.base.test.util.Feature; import org.chromium.base.test.util.parameter.ParameterizedTest; import org.chromium.content.browser.BindingManager; +import org.chromium.content.browser.ChildProcessConnection; import org.chromium.content.browser.ChildProcessLauncher; -import org.chromium.content.browser.ManagedChildProcessConnection; import org.chromium.content_public.common.ContentUrlConstants; import org.chromium.net.test.EmbeddedTestServer; import org.chromium.net.test.util.TestWebServer; @@ -585,7 +585,7 @@ } @Override - public void addNewConnection(int pid, ManagedChildProcessConnection connection) { + public void addNewConnection(int pid, ChildProcessConnection connection) { mIsChildProcessCreated = true; }
diff --git a/base/metrics/persistent_histogram_allocator.cc b/base/metrics/persistent_histogram_allocator.cc index ea1a2356..e23c635 100644 --- a/base/metrics/persistent_histogram_allocator.cc +++ b/base/metrics/persistent_histogram_allocator.cc
@@ -610,7 +610,7 @@ size_t counts_bytes = CalculateRequiredCountsBytes(histogram_bucket_count); PersistentMemoryAllocator::Reference counts_ref = - subtle::NoBarrier_Load(&histogram_data_ptr->counts_ref); + subtle::Acquire_Load(&histogram_data_ptr->counts_ref); if (counts_bytes == 0 || (counts_ref != 0 && memory_allocator_->GetAllocSize(counts_ref) < counts_bytes)) {
diff --git a/base/metrics/persistent_memory_allocator.cc b/base/metrics/persistent_memory_allocator.cc index 3c5198a..deb82ac 100644 --- a/base/metrics/persistent_memory_allocator.cc +++ b/base/metrics/persistent_memory_allocator.cc
@@ -1133,7 +1133,7 @@ void* DelayedPersistentAllocation::Get() const { // Relaxed operations are acceptable here because it's not protecting the // contents of the allocation in any way. - Reference ref = reference_->load(std::memory_order_relaxed); + Reference ref = reference_->load(std::memory_order_acquire); if (!ref) { ref = allocator_->Allocate(size_, type_); if (!ref) @@ -1144,7 +1144,7 @@ // cannot be retried. Reference existing = 0; // Must be mutable; receives actual value. if (reference_->compare_exchange_strong(existing, ref, - std::memory_order_relaxed, + std::memory_order_release, std::memory_order_relaxed)) { if (make_iterable_) allocator_->MakeIterable(ref);
diff --git a/base/metrics/persistent_memory_allocator.h b/base/metrics/persistent_memory_allocator.h index b931b2f..b7e7bd08 100644 --- a/base/metrics/persistent_memory_allocator.h +++ b/base/metrics/persistent_memory_allocator.h
@@ -793,7 +793,8 @@ // Once allocated, a reference to the segment will be stored at |ref|. // This shared location must be initialized to zero (0); it is checked // with every Get() request to see if the allocation has already been - // done. + // done. If reading |ref| outside of this object, be sure to do an + // "acquire" load. Don't write to it -- leave that to this object. // // For convenience, methods taking both Atomic32 and std::atomic<Reference> // are defined.
diff --git a/build/args/headless.gn b/build/args/headless.gn index 639c4f7..95979fc0 100644 --- a/build/args/headless.gn +++ b/build/args/headless.gn
@@ -15,6 +15,9 @@ # Embed resource.pak into binary to simplify deployment. headless_use_embedded_resources = true +# Expose headless bindings for freetype library bundled with Chromium. +headless_fontconfig_utils = true + # In order to simplify deployment we build ICU data file # into binary. icu_use_data_file = false
diff --git a/cc/layers/picture_layer_unittest.cc b/cc/layers/picture_layer_unittest.cc index 203c8dc..f976ab9f 100644 --- a/cc/layers/picture_layer_unittest.cc +++ b/cc/layers/picture_layer_unittest.cc
@@ -308,7 +308,6 @@ auto animation_host2 = AnimationHost::CreateForTesting(ThreadInstance::MAIN); - // TODO(sad): InitParams will be movable. LayerTreeHost::InitParams params2; params2.client = &host_client1; params2.settings = &settings;
diff --git a/cc/trees/layer_tree_host.h b/cc/trees/layer_tree_host.h index 3919895..ea46b47 100644 --- a/cc/trees/layer_tree_host.h +++ b/cc/trees/layer_tree_host.h
@@ -67,8 +67,6 @@ class CC_EXPORT LayerTreeHost : public NON_EXPORTED_BASE(SurfaceReferenceOwner), public NON_EXPORTED_BASE(MutatorHostClient) { public: - // TODO(sad): InitParams should be a movable type so that it can be - // std::move()d to the Create* functions. struct CC_EXPORT InitParams { LayerTreeHostClient* client = nullptr; TaskGraphRunner* task_graph_runner = nullptr;
diff --git a/chrome/android/java/res/layout/download_manager_spinner_drop_down.xml b/chrome/android/java/res/layout/download_manager_spinner_drop_down.xml index bbd10e35..d93c24b 100644 --- a/chrome/android/java/res/layout/download_manager_spinner_drop_down.xml +++ b/chrome/android/java/res/layout/download_manager_spinner_drop_down.xml
@@ -8,6 +8,7 @@ android:layout_height="wrap_content" android:background="?android:attr/selectableItemBackground" android:gravity="center_vertical" + android:drawablePadding="16dp" android:minWidth="176dp" android:minHeight="48dp" android:paddingStart="16dp"
diff --git a/chrome/android/java/res/menu/download_manager_menu.xml b/chrome/android/java/res/menu/download_manager_menu.xml index 313c5ea..79f19ba 100644 --- a/chrome/android/java/res/menu/download_manager_menu.xml +++ b/chrome/android/java/res/menu/download_manager_menu.xml
@@ -8,6 +8,12 @@ <group android:id="@+id/normal_menu_group" > <item + android:id="@+id/info_menu_id" + android:icon="@drawable/btn_info" + android:title="@string/show_info" + android:visible="false" + chrome:showAsAction="ifRoom" /> + <item android:id="@+id/search_menu_id" android:icon="@drawable/ic_search" android:title="@string/search"
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ChromeFeatureList.java b/chrome/android/java/src/org/chromium/chrome/browser/ChromeFeatureList.java index d2cb332f..79ae686 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/ChromeFeatureList.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/ChromeFeatureList.java
@@ -168,6 +168,7 @@ // Android. public static final String DATA_REDUCTION_MAIN_MENU = "DataReductionProxyMainMenu"; public static final String DATA_REDUCTION_SITE_BREAKDOWN = "DataReductionProxySiteBreakdown"; + public static final String DOWNLOAD_HOME_SHOW_STORAGE_INFO = "DownloadHomeShowStorageInfo"; // When enabled, fullscreen WebContents will be moved to a new Activity. Coming soon... public static final String FULLSCREEN_ACTIVITY = "FullscreenActivity"; // Whether we show an important sites dialog in the "Clear Browsing Data" flow.
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/compositor/bottombar/contextualsearch/ContextualSearchPanel.java b/chrome/android/java/src/org/chromium/chrome/browser/compositor/bottombar/contextualsearch/ContextualSearchPanel.java index 58e0a44..ca02f02 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/compositor/bottombar/contextualsearch/ContextualSearchPanel.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/compositor/bottombar/contextualsearch/ContextualSearchPanel.java
@@ -533,6 +533,16 @@ return super.getPanelState(); } + @Override + public void requestPanelShow(StateChangeReason reason) { + // If a re-tap is causing the panel to show when already shown, the superclass may ignore + // that, but we want to be sure to capture search metrics for each tap. + if (isShowing() && getPanelState() == PanelState.PEEKED) { + peekPanel(reason); + } + super.requestPanelShow(reason); + } + /** * Gets whether a touch on the content view has been done yet or not. */
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/download/ui/DownloadHistoryAdapter.java b/chrome/android/java/src/org/chromium/chrome/browser/download/ui/DownloadHistoryAdapter.java index ffd9d6e..c51fdb5 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/download/ui/DownloadHistoryAdapter.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/download/ui/DownloadHistoryAdapter.java
@@ -11,10 +11,12 @@ import android.view.LayoutInflater; import android.view.ViewGroup; +import org.chromium.base.ContextUtils; import org.chromium.base.ObserverList; import org.chromium.base.metrics.RecordHistogram; import org.chromium.base.metrics.RecordUserAction; import org.chromium.chrome.R; +import org.chromium.chrome.browser.ChromeFeatureList; import org.chromium.chrome.browser.download.DownloadItem; import org.chromium.chrome.browser.download.DownloadSharedPreferenceHelper; import org.chromium.chrome.browser.download.DownloadUtils; @@ -141,6 +143,9 @@ private static final String EMPTY_QUERY = null; + private static final String PREF_SHOW_STORAGE_INFO_HEADER = + "download_home_show_storage_info_header"; + private final BackendItems mRegularDownloadItems = new BackendItemsImpl(); private final BackendItems mIncognitoDownloadItems = new BackendItemsImpl(); private final BackendItems mOfflinePageItems = new BackendItemsImpl(); @@ -161,6 +166,7 @@ private String mSearchQuery = EMPTY_QUERY; private SpaceDisplay mSpaceDisplay; private boolean mIsSearching; + private boolean mShouldShowStorageInfoHeader; @Nullable // This may be null during tests. private UiConfig mUiConfig; @@ -196,6 +202,9 @@ initializeOfflinePageBridge(); sDeletedFileTracker.incrementInstanceCount(); + mShouldShowStorageInfoHeader = ContextUtils.getAppSharedPreferences().getBoolean( + PREF_SHOW_STORAGE_INFO_HEADER, + ChromeFeatureList.isEnabled(ChromeFeatureList.DOWNLOAD_HOME_SHOW_STORAGE_INFO)); } /** Called when the user's regular or incognito download history has been loaded. */ @@ -531,6 +540,26 @@ filter(mFilter); } + /** @return Whether the storage info header should be visible. */ + boolean shouldShowStorageInfoHeader() { + return mShouldShowStorageInfoHeader; + } + + /** + * Sets the visibility of the storage info header and saves user selection to shared preference. + * @param show Whether or not we should show the storage info header. + */ + void setShowStorageInfoHeader(boolean show) { + mShouldShowStorageInfoHeader = show; + ContextUtils.getAppSharedPreferences() + .edit() + .putBoolean(PREF_SHOW_STORAGE_INFO_HEADER, mShouldShowStorageInfoHeader) + .apply(); + RecordHistogram.recordBooleanHistogram( + "Android.DownloadManager.ShowStorageInfo", mShouldShowStorageInfoHeader); + filter(mFilter); + } + private DownloadDelegate getDownloadDelegate() { return mBackendProvider.getDownloadDelegate(); } @@ -560,7 +589,10 @@ } clear(false); - if (!filteredTimedItems.isEmpty() && !mIsSearching) addHeader(); + if (!filteredTimedItems.isEmpty() && !mIsSearching && mShouldShowStorageInfoHeader) { + addHeader(); + } + loadItems(filteredTimedItems); }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/download/ui/DownloadManagerToolbar.java b/chrome/android/java/src/org/chromium/chrome/browser/download/ui/DownloadManagerToolbar.java index 5ed4974..9006d97 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/download/ui/DownloadManagerToolbar.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/download/ui/DownloadManagerToolbar.java
@@ -85,7 +85,15 @@ } @Override - public void onManagerDestroyed() { } + protected void onDataChanged(int numItems) { + super.onDataChanged(numItems); + getMenu().findItem(R.id.info_menu_id).setVisible(numItems > 0); + } + + @Override + public void onManagerDestroyed() { + mSpinner.setAdapter(null); + } @Override public void showSearchView() {
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/download/ui/DownloadManagerUi.java b/chrome/android/java/src/org/chromium/chrome/browser/download/ui/DownloadManagerUi.java index 031a6f2..15ca52f 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/download/ui/DownloadManagerUi.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/download/ui/DownloadManagerUi.java
@@ -8,6 +8,7 @@ import android.content.ComponentName; import android.content.Intent; import android.content.res.Resources; +import android.graphics.drawable.Drawable; import android.os.AsyncTask; import android.support.graphics.drawable.VectorDrawableCompat; import android.support.v7.widget.RecyclerView; @@ -31,6 +32,7 @@ import org.chromium.chrome.browser.snackbar.Snackbar; import org.chromium.chrome.browser.snackbar.SnackbarManager; import org.chromium.chrome.browser.snackbar.SnackbarManager.SnackbarController; +import org.chromium.chrome.browser.widget.TintedDrawable; import org.chromium.chrome.browser.widget.selection.SelectableListLayout; import org.chromium.chrome.browser.widget.selection.SelectableListToolbar; import org.chromium.chrome.browser.widget.selection.SelectableListToolbar.SearchDelegate; @@ -221,6 +223,7 @@ addObserver(mHistoryAdapter); mUndoDeletionSnackbarController = new UndoDeletionSnackbarController(); + enableStorageInfoHeader(mHistoryAdapter.shouldShowStorageInfoHeader()); mIsSeparateActivity = isSeparateActivity; if (!mIsSeparateActivity) mToolbar.removeCloseButton(); @@ -302,6 +305,9 @@ } else if (item.getItemId() == R.id.selection_mode_share_menu_id) { shareSelectedItems(); return true; + } else if (item.getItemId() == R.id.info_menu_id) { + enableStorageInfoHeader(!mHistoryAdapter.shouldShowStorageInfoHeader()); + return true; } else if (item.getItemId() == R.id.search_menu_id) { // The header should be removed as soon as a search is started. It will be added back in // DownloadHistoryAdatper#filter() when the search is ended. @@ -385,6 +391,16 @@ mBackendProvider.getSelectionDelegate().clearSelection(); } + private void enableStorageInfoHeader(boolean show) { + mHistoryAdapter.setShowStorageInfoHeader(show); + MenuItem infoMenuItem = mToolbar.getMenu().findItem(R.id.info_menu_id); + Drawable iconDrawable = TintedDrawable.constructTintedDrawable(mActivity.getResources(), + R.drawable.btn_info, + show ? R.color.light_active_color : R.color.default_text_color); + infoMenuItem.setIcon(iconDrawable); + infoMenuItem.setTitle(show ? R.string.hide_info : R.string.show_info); + } + /** * @return An Intent to share the selected items. */
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/download/ui/FilterAdapter.java b/chrome/android/java/src/org/chromium/chrome/browser/download/ui/FilterAdapter.java index 3a155c8d..7b8cf0c 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/download/ui/FilterAdapter.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/download/ui/FilterAdapter.java
@@ -4,6 +4,7 @@ package org.chromium.chrome.browser.download.ui; +import android.graphics.drawable.Drawable; import android.support.annotation.LayoutRes; import android.view.LayoutInflater; import android.view.View; @@ -14,6 +15,7 @@ import org.chromium.chrome.R; import org.chromium.chrome.browser.download.ui.DownloadManagerUi.DownloadUiObserver; +import org.chromium.chrome.browser.widget.TintedDrawable; /** An adapter that allows selecting an item from a dropdown spinner. */ class FilterAdapter @@ -40,6 +42,11 @@ TextView labelView = getTextViewFromResource(convertView, R.layout.download_manager_spinner_drop_down); labelView.setText(DownloadFilter.getStringIdForFilter(position)); + int iconId = DownloadFilter.getDrawableForFilter(position); + Drawable iconDrawable = TintedDrawable.constructTintedDrawable( + mManagerUi.getActivity().getResources(), iconId, R.color.descriptive_text_color); + labelView.setCompoundDrawablesWithIntrinsicBounds(iconDrawable, null, null, null); + return labelView; }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/notifications/NotificationBuilderFactory.java b/chrome/android/java/src/org/chromium/chrome/browser/notifications/NotificationBuilderFactory.java index c6794917..9bcc2dc 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/notifications/NotificationBuilderFactory.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/notifications/NotificationBuilderFactory.java
@@ -48,6 +48,6 @@ return new NotificationBuilderForO(context, channelId, new ChannelsInitializer(new NotificationManagerProxyImpl(context.getSystemService( NotificationManager.class)), - new ChannelDefinitions())); + context.getResources())); } }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/notifications/NotificationManagerProxy.java b/chrome/android/java/src/org/chromium/chrome/browser/notifications/NotificationManagerProxy.java index 5070fedc..59e2f5b 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/notifications/NotificationManagerProxy.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/notifications/NotificationManagerProxy.java
@@ -6,6 +6,7 @@ import android.app.Notification; +import org.chromium.chrome.browser.notifications.channels.Channel; import org.chromium.chrome.browser.notifications.channels.ChannelDefinitions; import java.util.List; @@ -14,16 +15,17 @@ * A proxy for the Android Notification Manager. This allows tests to be written without having to * use the real Notification Manager. * - * @see http://developer.android.com/reference/android/app/NotificationManager.html + * @see <a href="https://developer.android.com/reference/android/app/NotificationManager.html"> + * https://developer.android.com/reference/android/app/NotificationManager.html</a> */ public interface NotificationManagerProxy { void cancel(int id); void cancel(String tag, int id); void cancelAll(); - void createNotificationChannel(ChannelDefinitions.Channel channel); + void createNotificationChannel(Channel channel); void createNotificationChannelGroup(ChannelDefinitions.ChannelGroup channelGroup); - List<String> getNotificationChannelIds(); - void deleteNotificationChannel(@ChannelDefinitions.ChannelId String id); + List<Channel> getNotificationChannels(); + void deleteNotificationChannel(String id); void notify(int id, Notification notification); void notify(String tag, int id, Notification notification);
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/notifications/NotificationManagerProxyImpl.java b/chrome/android/java/src/org/chromium/chrome/browser/notifications/NotificationManagerProxyImpl.java index f9f8e5a..edc8e9c 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/notifications/NotificationManagerProxyImpl.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/notifications/NotificationManagerProxyImpl.java
@@ -4,12 +4,14 @@ package org.chromium.chrome.browser.notifications; +import android.annotation.SuppressLint; import android.app.Notification; import android.app.NotificationManager; import org.chromium.base.BuildInfo; import org.chromium.base.ContextUtils; import org.chromium.base.Log; +import org.chromium.chrome.browser.notifications.channels.Channel; import org.chromium.chrome.browser.notifications.channels.ChannelDefinitions; import java.lang.reflect.Constructor; @@ -45,16 +47,19 @@ mNotificationManager.cancelAll(); } + @SuppressLint("NewApi") @Override - public void createNotificationChannel(ChannelDefinitions.Channel channel) { + public void createNotificationChannel(Channel channel) { assert BuildInfo.isAtLeastO(); /* The code in the try-block uses reflection in order to compile as it calls APIs newer than our compileSdkVersion of Android. The equivalent code without reflection looks like this: - channel.setGroup(channelGroupId); - channel.setShowBadge(false); - mNotificationManager.createNotificationChannel(channel); + NotificationChannel nc = new NotificationChannel(channel.getId(), channel.getName(), + channel.getImportance()); + nc.setGroup(channel.getGroupId()); + nc.setShowBadge(false); + mNotificationManager.createNotificationChannel(nc); */ // TODO(crbug.com/707804) Stop using reflection once compileSdkVersion is high enough. try { @@ -62,13 +67,12 @@ Class<?> channelClass = Class.forName("android.app.NotificationChannel"); Constructor<?> channelConstructor = channelClass.getDeclaredConstructor( String.class, CharSequence.class, int.class); - Object channelObject = channelConstructor.newInstance(channel.mId, - ContextUtils.getApplicationContext().getString(channel.mNameResId), - channel.mImportance); + Object channelObject = channelConstructor.newInstance( + channel.getId(), channel.getName(), channel.getImportance()); // Set group on channel Method setGroupMethod = channelClass.getMethod("setGroup", String.class); - setGroupMethod.invoke(channelObject, channel.mGroupId); + setGroupMethod.invoke(channelObject, channel.getGroupId()); // Set channel to not badge on app icon Method setShowBadgeMethod = channelClass.getMethod("setShowBadge", boolean.class); @@ -85,6 +89,7 @@ } } + @SuppressLint("NewApi") @Override public void createNotificationChannelGroup(ChannelDefinitions.ChannelGroup channelGroup) { assert BuildInfo.isAtLeastO(); @@ -114,17 +119,19 @@ } } + @SuppressLint("NewApi") @Override - public List<String> getNotificationChannelIds() { + public List<Channel> getNotificationChannels() { assert BuildInfo.isAtLeastO(); - List<String> channelIds = new ArrayList<>(); + List<Channel> channels = new ArrayList<>(); /* The code in the try-block uses reflection in order to compile as it calls APIs newer than our compileSdkVersion of Android. The equivalent code without reflection looks like this: List<NotificationChannel> list = mNotificationManager.getNotificationChannels(); - for (NotificationChannel channel : list) { - channelIds.add(channel.getId()); + for (NotificationChannel nc : list) { + list.add(new Channel( + nc.getId(), nc.getName(), nc.getImportance(), nc.getGroupId())); } */ // TODO(crbug.com/707804) Stop using reflection once compileSdkVersion is high enough. @@ -133,16 +140,24 @@ List channelsList = (List) method.invoke(mNotificationManager); for (Object o : channelsList) { Method getId = o.getClass().getMethod("getId"); - channelIds.add((String) getId.invoke(o)); + Method getName = o.getClass().getMethod("getName"); + Method getImportance = o.getClass().getMethod("getImportance"); + Method getGroup = o.getClass().getMethod("getGroup"); + String channelId = (String) getId.invoke(o); + String name = (String) getName.invoke(o); + int importance = (int) getImportance.invoke(o); + String groupId = (String) getGroup.invoke(o); + channels.add(new Channel(channelId, name, importance, groupId)); } } catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException e) { Log.e(TAG, "Error getting notification channels:", e); } - return channelIds; + return channels; } + @SuppressLint("NewApi") @Override - public void deleteNotificationChannel(@ChannelDefinitions.ChannelId String id) { + public void deleteNotificationChannel(String id) { assert BuildInfo.isAtLeastO(); /* The code in the try-block uses reflection in order to compile as it calls APIs newer than
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/notifications/channels/Channel.java b/chrome/android/java/src/org/chromium/chrome/browser/notifications/channels/Channel.java new file mode 100644 index 0000000..63d0c8cc --- /dev/null +++ b/chrome/android/java/src/org/chromium/chrome/browser/notifications/channels/Channel.java
@@ -0,0 +1,41 @@ +// Copyright 2017 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.notifications.channels; + +/** + * Helper class that corresponds to the Android NotificationChannel class, + * which we cannot use directly until our compileSdkVersion is bumped to O. + * + * Only the methods & properties we use have been added, others may be added if the need arises. + */ +public class Channel { + private final String mId; + private final CharSequence mName; + private final int mImportance; + private final String mGroupId; + + public Channel(String id, CharSequence name, int importance, String groupId) { + mId = id; + mName = name; + mImportance = importance; + mGroupId = groupId; + } + + public String getId() { + return mId; + } + + public CharSequence getName() { + return mName; + } + + public int getImportance() { + return mImportance; + } + + public String getGroupId() { + return mGroupId; + } +} \ No newline at end of file
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/notifications/channels/ChannelDefinitions.java b/chrome/android/java/src/org/chromium/chrome/browser/notifications/channels/ChannelDefinitions.java index 81976b4..3744a679 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/notifications/channels/ChannelDefinitions.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/notifications/channels/ChannelDefinitions.java
@@ -6,6 +6,7 @@ import android.annotation.TargetApi; import android.app.NotificationManager; +import android.content.res.Resources; import android.os.Build; import android.support.annotation.StringDef; @@ -61,27 +62,27 @@ * incremented every time an entry is modified, removed or added to this map. * If an entry is removed from here then it must be added to the LEGACY_CHANNEL_IDs array. */ - static final Map<String, Channel> MAP; + static final Map<String, PredefinedChannel> MAP; static { - Map<String, Channel> map = new HashMap<>(); + Map<String, PredefinedChannel> map = new HashMap<>(); map.put(CHANNEL_ID_BROWSER, - new Channel(CHANNEL_ID_BROWSER, + new PredefinedChannel(CHANNEL_ID_BROWSER, org.chromium.chrome.R.string.notification_category_browser, NotificationManager.IMPORTANCE_LOW, CHANNEL_GROUP_ID_GENERAL)); map.put(CHANNEL_ID_DOWNLOADS, - new Channel(CHANNEL_ID_DOWNLOADS, + new PredefinedChannel(CHANNEL_ID_DOWNLOADS, org.chromium.chrome.R.string.notification_category_downloads, NotificationManager.IMPORTANCE_LOW, CHANNEL_GROUP_ID_GENERAL)); map.put(CHANNEL_ID_INCOGNITO, - new Channel(CHANNEL_ID_INCOGNITO, + new PredefinedChannel(CHANNEL_ID_INCOGNITO, org.chromium.chrome.R.string.notification_category_incognito, NotificationManager.IMPORTANCE_LOW, CHANNEL_GROUP_ID_GENERAL)); map.put(CHANNEL_ID_MEDIA, - new Channel(CHANNEL_ID_MEDIA, + new PredefinedChannel(CHANNEL_ID_MEDIA, org.chromium.chrome.R.string.notification_category_media, NotificationManager.IMPORTANCE_LOW, CHANNEL_GROUP_ID_GENERAL)); map.put(CHANNEL_ID_SITES, - new Channel(CHANNEL_ID_SITES, + new PredefinedChannel(CHANNEL_ID_SITES, org.chromium.chrome.R.string.notification_category_sites, NotificationManager.IMPORTANCE_DEFAULT, CHANNEL_GROUP_ID_GENERAL)); MAP = Collections.unmodifiableMap(map); @@ -110,7 +111,7 @@ /** * @return A set of channel ids of channels that should be initialized on startup. */ - Set<String> getStartupChannelIds() { + static Set<String> getStartupChannelIds() { // CHANNELS_VERSION must be incremented if the set of channels returned here changes. return PredefinedChannels.MAP.keySet(); } @@ -119,36 +120,42 @@ * @return An array of old ChannelIds that may have been returned by * {@link #getStartupChannelIds} in the past, but are no longer in use. */ - public String[] getLegacyChannelIds() { + static String[] getLegacyChannelIds() { return LEGACY_CHANNEL_IDS; } - ChannelGroup getChannelGroupFromId(Channel channel) { + static ChannelGroup getChannelGroupFromId(PredefinedChannel channel) { return PredefinedChannelGroups.MAP.get(channel.mGroupId); } - Channel getChannelFromId(@ChannelId String channelId) { + static PredefinedChannel getChannelFromId(@ChannelId String channelId) { return PredefinedChannels.MAP.get(channelId); } /** - * Helper class containing notification channel properties. + * Helper class for storing predefined channel properties while allowing the channel name to be + * lazily evaluated only when it is converted to an actual (Notification)Channel. */ - public static class Channel { + static class PredefinedChannel { @ChannelId - public final String mId; - public final int mNameResId; - public final int mImportance; + private final String mId; + private final int mNameResId; + private final int mImportance; @ChannelGroupId - public final String mGroupId; + private final String mGroupId; - Channel(@ChannelId String id, int nameResId, int importance, + PredefinedChannel(@ChannelId String id, int nameResId, int importance, @ChannelGroupId String groupId) { this.mId = id; this.mNameResId = nameResId; this.mImportance = importance; this.mGroupId = groupId; } + + Channel toChannel(Resources resources) { + String name = resources.getString(mNameResId); + return new Channel(mId, name, mImportance, mGroupId); + } } /**
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/notifications/channels/ChannelsInitializer.java b/chrome/android/java/src/org/chromium/chrome/browser/notifications/channels/ChannelsInitializer.java index d7a9d36a..e88a699c 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/notifications/channels/ChannelsInitializer.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/notifications/channels/ChannelsInitializer.java
@@ -4,6 +4,8 @@ package org.chromium.chrome.browser.notifications.channels; +import android.content.res.Resources; + import org.chromium.chrome.browser.notifications.NotificationManagerProxy; /** @@ -11,20 +13,20 @@ */ public class ChannelsInitializer { private final NotificationManagerProxy mNotificationManager; - private final ChannelDefinitions mChannelDefinitions; + private final Resources mResources; - public ChannelsInitializer(NotificationManagerProxy notificationManagerProxy, - ChannelDefinitions channelDefinitions) { + public ChannelsInitializer( + NotificationManagerProxy notificationManagerProxy, Resources resources) { mNotificationManager = notificationManagerProxy; - mChannelDefinitions = channelDefinitions; + mResources = resources; } /** * Creates all the channels on the notification manager that we want to appear in our * channel settings from first launch onwards. */ - public void initializeStartupChannels() { - for (String channelId : mChannelDefinitions.getStartupChannelIds()) { + void initializeStartupChannels() { + for (String channelId : ChannelDefinitions.getStartupChannelIds()) { ensureInitialized(channelId); } } @@ -34,7 +36,7 @@ * It's safe to call this multiple times since deleting an already-deleted channel is a no-op. */ void deleteLegacyChannels() { - for (String channelId : mChannelDefinitions.getLegacyChannelIds()) { + for (String channelId : ChannelDefinitions.getLegacyChannelIds()) { mNotificationManager.deleteNotificationChannel(channelId); } } @@ -49,13 +51,14 @@ * @param channelId The ID of the channel to be initialized. */ public void ensureInitialized(@ChannelDefinitions.ChannelId String channelId) { - ChannelDefinitions.Channel channel = mChannelDefinitions.getChannelFromId(channelId); - if (channel == null) { + ChannelDefinitions.PredefinedChannel predefinedChannel = + ChannelDefinitions.getChannelFromId(channelId); + if (predefinedChannel == null) { throw new IllegalStateException("Could not initialize channel: " + channelId); } // Channel group must be created before the channel. mNotificationManager.createNotificationChannelGroup( - mChannelDefinitions.getChannelGroupFromId(channel)); - mNotificationManager.createNotificationChannel(channel); + ChannelDefinitions.getChannelGroupFromId(predefinedChannel)); + mNotificationManager.createNotificationChannel(predefinedChannel.toChannel(mResources)); } }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/notifications/channels/ChannelsUpdater.java b/chrome/android/java/src/org/chromium/chrome/browser/notifications/channels/ChannelsUpdater.java index cbec962..e8401430 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/notifications/channels/ChannelsUpdater.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/notifications/channels/ChannelsUpdater.java
@@ -39,7 +39,7 @@ new NotificationManagerProxyImpl( (NotificationManager) ContextUtils.getApplicationContext() .getSystemService(Context.NOTIFICATION_SERVICE)), - new ChannelDefinitions()), + ContextUtils.getApplicationContext().getResources()), ChannelDefinitions.CHANNELS_VERSION); }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ntp/NewTabPageView.java b/chrome/android/java/src/org/chromium/chrome/browser/ntp/NewTabPageView.java index 5a5d768..5993449 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/ntp/NewTabPageView.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/ntp/NewTabPageView.java
@@ -17,8 +17,10 @@ import android.text.Editable; import android.text.TextWatcher; import android.util.AttributeSet; +import android.util.TypedValue; import android.view.MotionEvent; import android.view.View; +import android.view.ViewGroup; import android.view.ViewStub; import android.widget.FrameLayout; import android.widget.ImageView; @@ -80,6 +82,16 @@ private static final String PARAM_CONDENSED_TILE_LAYOUT_FOR_LARGE_SCREENS_ENABLED = "condensed_tile_layout_for_large_screens_enabled"; + /** + * Experiment parameter for whether to show the logo in the condensed layout. + */ + private static final String PARAM_CONDENSED_LAYOUT_SHOW_LOGO = "condensed_layout_show_logo"; + + /** + * Experiment parameter for the logo height in dp in the condensed layout. + */ + private static final String PARAM_CONDENSED_LAYOUT_LOGO_HEIGHT = "condensed_layout_logo_height"; + private NewTabPageRecyclerView mRecyclerView; private NewTabPageLayout mNewTabPageLayout; @@ -244,7 +256,15 @@ mSearchProviderLogoView = (LogoView) mNewTabPageLayout.findViewById(R.id.search_provider_logo); + int experimentalLogoHeightDp = ChromeFeatureList.getFieldTrialParamByFeatureAsInt( + ChromeFeatureList.NTP_CONDENSED_LAYOUT, PARAM_CONDENSED_LAYOUT_LOGO_HEIGHT, 0); + if (experimentalLogoHeightDp > 0) { + ViewGroup.LayoutParams logoParams = mSearchProviderLogoView.getLayoutParams(); + logoParams.height = dpToPx(experimentalLogoHeightDp); + mSearchProviderLogoView.setLayoutParams(logoParams); + } mLogoDelegate = new LogoDelegateImpl(tab, mSearchProviderLogoView); + mSearchBoxView = mNewTabPageLayout.findViewById(R.id.search_box); mNoSearchLogoSpacer = mNewTabPageLayout.findViewById(R.id.no_search_logo_spacer); @@ -559,11 +579,9 @@ public void setSearchProviderHasLogo(boolean hasLogo) { if (hasLogo == mSearchProviderHasLogo && mInitialized) return; mSearchProviderHasLogo = hasLogo; - boolean showLogo = mSearchProviderHasLogo - && !ChromeFeatureList.isEnabled(ChromeFeatureList.NTP_CONDENSED_LAYOUT); // Set a bit more top padding on the tile grid if there is no logo. - int paddingTop = getResources().getDimensionPixelSize(showLogo + int paddingTop = getResources().getDimensionPixelSize(shouldShowLogo() ? R.dimen.tile_grid_layout_padding_top : R.dimen.tile_grid_layout_no_logo_padding_top); mTileGridLayout.setPadding(0, paddingTop, 0, mTileGridLayout.getPaddingBottom()); @@ -571,7 +589,7 @@ // Hide or show the views above the tile grid as needed, including logo, search box, and // spacers. int visibility = mSearchProviderHasLogo ? View.VISIBLE : View.GONE; - int logoVisibility = showLogo ? View.VISIBLE : View.GONE; + int logoVisibility = shouldShowLogo() ? View.VISIBLE : View.GONE; int childCount = mNewTabPageLayout.getChildCount(); for (int i = 0; i < childCount; i++) { View child = mNewTabPageLayout.getChildAt(i); @@ -850,6 +868,14 @@ PARAM_CONDENSED_TILE_LAYOUT_FOR_LARGE_SCREENS_ENABLED, false); } + private boolean shouldShowLogo() { + boolean condensedLayoutEnabled = + ChromeFeatureList.isEnabled(ChromeFeatureList.NTP_CONDENSED_LAYOUT); + boolean showLogoInCondensedLayout = ChromeFeatureList.getFieldTrialParamByFeatureAsBoolean( + ChromeFeatureList.NTP_CONDENSED_LAYOUT, PARAM_CONDENSED_LAYOUT_SHOW_LOGO, false); + return mSearchProviderHasLogo && (!condensedLayoutEnabled || showLogoInCondensedLayout); + } + @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { if (mNewTabPageLayout != null) { @@ -929,4 +955,12 @@ updateSearchBoxOnScroll(); } } + + /** + * Converts a dp value to a px value. + */ + private int dpToPx(int value) { + return Math.round(TypedValue.applyDimension( + TypedValue.COMPLEX_UNIT_DIP, value, getResources().getDisplayMetrics())); + } }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/offlinepages/OfflinePageBridge.java b/chrome/android/java/src/org/chromium/chrome/browser/offlinepages/OfflinePageBridge.java index 8c09c2a..6b0c14a 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/offlinepages/OfflinePageBridge.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/offlinepages/OfflinePageBridge.java
@@ -11,6 +11,7 @@ import org.chromium.base.annotations.CalledByNative; import org.chromium.base.annotations.JNINamespace; import org.chromium.chrome.browser.profiles.Profile; +import org.chromium.components.offlinepages.DeletePageResult; import org.chromium.content_public.browser.WebContents; import java.util.ArrayList; @@ -191,6 +192,19 @@ } /** + * Gets the offline pages associated with the provided namespace. + * + * @param namespace The string form of the namespace to query. + * @return A list of {@link OfflinePageItem} matching the provided namespace, or an empty list + * if none exist. + */ + public void getPagesForNamespace( + final String namespace, final Callback<List<OfflinePageItem>> callback) { + List<OfflinePageItem> result = new ArrayList<>(); + nativeGetPagesForNamespace(mNativeOfflinePageBridge, result, namespace, callback); + } + + /** * Gets all the URLs in the request queue. * * @return A list of {@link SavePageRequest} representing all the queued requests. @@ -381,6 +395,29 @@ } /** + * Deletes offline pages based on the list of offline IDs. Calls the callback + * when operation is complete. Note that offline IDs are not intended to be saved across + * restarts of Chrome; they should be obtained by querying the model for the appropriate client + * ID. + * + * @param offlineIds A list of offline IDs of pages that will be deleted. + * @param callback A callback that will be called once operation is completed, called with the + * DeletePageResult of the operation.. + */ + public void deletePagesByOfflineId(List<Long> offlineIdList, Callback<Integer> callback) { + if (offlineIdList == null) { + callback.onResult(Integer.valueOf(DeletePageResult.SUCCESS)); + return; + } + + long[] offlineIds = new long[offlineIdList.size()]; + for (int i = 0; i < offlineIdList.size(); i++) { + offlineIds[i] = offlineIdList.get(i).longValue(); + } + nativeDeletePagesByOfflineId(mNativeOfflinePageBridge, offlineIds, callback); + } + + /** * Whether or not the underlying offline page model is loaded. */ public boolean isOfflinePageModelLoaded() { @@ -564,6 +601,7 @@ private native void nativeRegisterRecentTab(long nativeOfflinePageBridge, int tabId); private native void nativeWillCloseTab(long nativeOfflinePageBridge, WebContents webContents); private native void nativeUnregisterRecentTab(long nativeOfflinePageBridge, int tabId); + @VisibleForTesting native void nativeGetRequestsInQueue( long nativeOfflinePageBridge, Callback<SavePageRequest[]> callback); @@ -576,9 +614,16 @@ @VisibleForTesting native void nativeGetPagesByClientId(long nativeOfflinePageBridge, List<OfflinePageItem> result, String[] namespaces, String[] ids, Callback<List<OfflinePageItem>> callback); + native void nativeGetPagesForNamespace(long nativeOfflinePageBridge, + List<OfflinePageItem> result, String nameSpace, + Callback<List<OfflinePageItem>> callback); @VisibleForTesting native void nativeDeletePagesByClientId(long nativeOfflinePageBridge, String[] namespaces, String[] ids, Callback<Integer> callback); + @VisibleForTesting + native void nativeDeletePagesByOfflineId( + long nativeOfflinePageBridge, long[] offlineIds, Callback<Integer> callback); + private native void nativeSelectPageForOnlineUrl( long nativeOfflinePageBridge, String onlineUrl, int tabId, Callback<OfflinePageItem> callback);
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/payments/ui/EditorView.java b/chrome/android/java/src/org/chromium/chrome/browser/payments/ui/EditorView.java index 3c9164b..a4a0dda8 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/payments/ui/EditorView.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/payments/ui/EditorView.java
@@ -26,6 +26,7 @@ import android.view.View; import android.view.View.OnClickListener; import android.view.ViewGroup; +import android.view.WindowManager; import android.view.inputmethod.EditorInfo; import android.widget.Button; import android.widget.CheckBox; @@ -153,6 +154,13 @@ mPhoneFormatter = new PhoneNumberUtil.FormatTextWatcher(); } + /** Prevents screenshots of this editor. */ + public void disableScreenshots() { + WindowManager.LayoutParams attributes = getWindow().getAttributes(); + attributes.flags |= WindowManager.LayoutParams.FLAG_SECURE; + getWindow().setAttributes(attributes); + } + /** Launches the Autofill help page on top of the current Context. */ public static void launchAutofillHelpPage(Context context) { CustomTabActivity.showInfoPage(context, HELP_URL);
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/payments/ui/PaymentRequestUI.java b/chrome/android/java/src/org/chromium/chrome/browser/payments/ui/PaymentRequestUI.java index f8272db..df99097 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/payments/ui/PaymentRequestUI.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/payments/ui/PaymentRequestUI.java
@@ -42,6 +42,7 @@ import org.chromium.base.Callback; import org.chromium.base.VisibleForTesting; import org.chromium.chrome.R; +import org.chromium.chrome.browser.ChromeVersionInfo; import org.chromium.chrome.browser.payments.ShippingStrings; import org.chromium.chrome.browser.payments.ui.PaymentRequestSection.LineItemBreakdownSection; import org.chromium.chrome.browser.payments.ui.PaymentRequestSection.OptionSection; @@ -437,6 +438,11 @@ mEditorView = new EditorView(activity, sObserverForTest); mCardEditorView = new EditorView(activity, sObserverForTest); + // Allow screenshots of the credit card number in Canary, Dev, and developer builds. + if (ChromeVersionInfo.isBetaBuild() || ChromeVersionInfo.isStableBuild()) { + mCardEditorView.disableScreenshots(); + } + // Set up the dialog. mDialog = new AlwaysDismissedDialog(activity, R.style.DialogWhenLarge); mDialog.setOnDismissListener(this);
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/preferences/autofill/AutofillLocalCardEditor.java b/chrome/android/java/src/org/chromium/chrome/browser/preferences/autofill/AutofillLocalCardEditor.java index 5b61177..56454e9f 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/preferences/autofill/AutofillLocalCardEditor.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/preferences/autofill/AutofillLocalCardEditor.java
@@ -10,6 +10,7 @@ import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; +import android.view.WindowManager; import android.widget.AdapterView; import android.widget.ArrayAdapter; import android.widget.Button; @@ -17,6 +18,7 @@ import android.widget.Spinner; import org.chromium.chrome.R; +import org.chromium.chrome.browser.ChromeVersionInfo; import org.chromium.chrome.browser.autofill.PersonalDataManager; import org.chromium.chrome.browser.autofill.PersonalDataManager.AutofillProfile; import org.chromium.chrome.browser.autofill.PersonalDataManager.CreditCard; @@ -43,6 +45,13 @@ @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { + // Allow screenshots of the credit card number in Canary, Dev, and developer builds. + if (ChromeVersionInfo.isBetaBuild() || ChromeVersionInfo.isStableBuild()) { + WindowManager.LayoutParams attributes = getActivity().getWindow().getAttributes(); + attributes.flags |= WindowManager.LayoutParams.FLAG_SECURE; + getActivity().getWindow().setAttributes(attributes); + } + View v = super.onCreateView(inflater, container, savedInstanceState); mNameLabel = (CompatibilityTextInputLayout) v.findViewById(R.id.credit_card_name_label);
diff --git a/chrome/android/java/strings/android_chrome_strings.grd b/chrome/android/java/strings/android_chrome_strings.grd index eab27a4..8cdba075 100644 --- a/chrome/android/java/strings/android_chrome_strings.grd +++ b/chrome/android/java/strings/android_chrome_strings.grd
@@ -209,6 +209,12 @@ <message name="IDS_SEARCH" desc="The label for a search button."> Search </message> + <message name="IDS_SHOW_INFO" desc="The label for a info button to show info."> + Show Info + </message> + <message name="IDS_HIDE_INFO" desc="The label for a info button to hide info."> + Hide Info + </message> <message name="IDS_COPY_LINK" desc="The label for a menu item to copy a link. [CHAR-LIMIT=30]"> Copy link </message>
diff --git a/chrome/android/java_sources.gni b/chrome/android/java_sources.gni index c9c0e20a..99bb6f6 100644 --- a/chrome/android/java_sources.gni +++ b/chrome/android/java_sources.gni
@@ -594,6 +594,7 @@ "java/src/org/chromium/chrome/browser/notifications/NotificationUmaTracker.java", "java/src/org/chromium/chrome/browser/notifications/StandardNotificationBuilder.java", "java/src/org/chromium/chrome/browser/notifications/WebApkNotificationClient.java", + "java/src/org/chromium/chrome/browser/notifications/channels/Channel.java", "java/src/org/chromium/chrome/browser/notifications/channels/ChannelDefinitions.java", "java/src/org/chromium/chrome/browser/notifications/channels/ChannelsInitializer.java", "java/src/org/chromium/chrome/browser/notifications/channels/ChannelsUpdater.java", @@ -1457,6 +1458,7 @@ "javatests/src/org/chromium/chrome/browser/notifications/NotificationTestUtil.java", "javatests/src/org/chromium/chrome/browser/notifications/StandardNotificationBuilderTest.java", "javatests/src/org/chromium/chrome/browser/notifications/NotificationBuilderBaseTest.java", + "javatests/src/org/chromium/chrome/browser/notifications/channels/ChannelsInitializerTest.java", "javatests/src/org/chromium/chrome/browser/ntp/ChromeHomeNewTabPageTest.java", "javatests/src/org/chromium/chrome/browser/ntp/NewTabPageNavigationTest.java", "javatests/src/org/chromium/chrome/browser/ntp/NewTabPageTest.java", @@ -1713,7 +1715,6 @@ "junit/src/org/chromium/chrome/browser/metrics/VariationsSessionTest.java", "junit/src/org/chromium/chrome/browser/notifications/NotificationPlatformBridgeUnitTest.java", "junit/src/org/chromium/chrome/browser/notifications/channels/ChannelDefinitionsTest.java", - "junit/src/org/chromium/chrome/browser/notifications/channels/ChannelsInitializerTest.java", "junit/src/org/chromium/chrome/browser/notifications/channels/ChannelsUpdaterTest.java", "junit/src/org/chromium/chrome/browser/ntp/NativePageFactoryTest.java", "junit/src/org/chromium/chrome/browser/ntp/TitleUtilTest.java",
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/BindingManagerIntegrationTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/BindingManagerIntegrationTest.java index cfaba43d3..dba4111b 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/BindingManagerIntegrationTest.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/BindingManagerIntegrationTest.java
@@ -34,8 +34,8 @@ import org.chromium.chrome.test.util.ChromeRestriction; import org.chromium.chrome.test.util.ChromeTabUtils; import org.chromium.content.browser.BindingManager; +import org.chromium.content.browser.ChildProcessConnection; import org.chromium.content.browser.ChildProcessLauncher; -import org.chromium.content.browser.ManagedChildProcessConnection; import org.chromium.content.browser.test.ChildProcessAllocatorSettings; import org.chromium.content.browser.test.util.Criteria; import org.chromium.content.browser.test.util.CriteriaHelper; @@ -113,7 +113,7 @@ } @Override - public void addNewConnection(int pid, ManagedChildProcessConnection connection) { + public void addNewConnection(int pid, ChildProcessConnection connection) { synchronized (mVisibilityCallsMap) { mVisibilityCallsMap.put(pid, ""); }
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/download/DownloadActivityTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/download/DownloadActivityTest.java index 851c84dd..dd20e4d 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/download/DownloadActivityTest.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/download/DownloadActivityTest.java
@@ -5,6 +5,7 @@ package org.chromium.chrome.browser.download; import android.content.Intent; +import android.content.SharedPreferences.Editor; import android.os.Handler; import android.os.Looper; import android.support.test.filters.MediumTest; @@ -15,6 +16,7 @@ import android.widget.Spinner; import android.widget.TextView; +import org.chromium.base.ContextUtils; import org.chromium.base.ThreadUtils; import org.chromium.base.test.BaseActivityInstrumentationTestCase; import org.chromium.base.test.util.CallbackHelper; @@ -108,6 +110,9 @@ } } + private static final String PREF_SHOW_STORAGE_INFO_HEADER = + "download_home_show_storage_info_header"; + private StubbedProvider mStubbedProvider; private TestObserver mAdapterObserver; private DownloadManagerUi mUi; @@ -124,6 +129,9 @@ public void setUp() throws Exception { super.setUp(); + Editor editor = ContextUtils.getAppSharedPreferences().edit(); + editor.putBoolean(PREF_SHOW_STORAGE_INFO_HEADER, true).apply(); + mStubbedProvider = new StubbedProvider(); DownloadManagerUi.setProviderForTests(mStubbedProvider);
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/download/ui/DownloadHistoryAdapterTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/download/ui/DownloadHistoryAdapterTest.java index aba0daa..591a2a1 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/download/ui/DownloadHistoryAdapterTest.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/download/ui/DownloadHistoryAdapterTest.java
@@ -8,6 +8,7 @@ import static org.chromium.chrome.browser.widget.DateDividedAdapter.TYPE_HEADER; import static org.chromium.chrome.browser.widget.DateDividedAdapter.TYPE_NORMAL; +import android.content.SharedPreferences.Editor; import android.support.test.filters.SmallTest; import android.support.v7.widget.RecyclerView; @@ -17,6 +18,7 @@ import org.junit.Test; import org.junit.runner.RunWith; +import org.chromium.base.ContextUtils; import org.chromium.base.ThreadUtils; import org.chromium.base.test.BaseJUnit4ClassRunner; import org.chromium.base.test.util.CallbackHelper; @@ -70,6 +72,9 @@ */ private static final Integer HEADER = -1; + private static final String PREF_SHOW_STORAGE_INFO_HEADER = + "download_home_show_storage_info_header"; + private DownloadHistoryAdapter mAdapter; private Observer mObserver; private StubbedDownloadDelegate mDownloadDelegate; @@ -82,6 +87,8 @@ mBackendProvider = new StubbedProvider(); mDownloadDelegate = mBackendProvider.getDownloadDelegate(); mOfflineDelegate = mBackendProvider.getOfflinePageBridge(); + Editor editor = ContextUtils.getAppSharedPreferences().edit(); + editor.putBoolean(PREF_SHOW_STORAGE_INFO_HEADER, true).apply(); } private void initializeAdapter(boolean showOffTheRecord) throws Exception { @@ -158,6 +165,50 @@ Assert.assertEquals(11, mAdapter.getTotalDownloadSize()); } + /** Storage header shouldn't show up if user has already turned it off. */ + @Test + @SmallTest + public void testInitialize_SingleItemNoStorageHeader() throws Exception { + Editor editor = ContextUtils.getAppSharedPreferences().edit(); + editor.putBoolean(PREF_SHOW_STORAGE_INFO_HEADER, false).apply(); + DownloadItem item = StubbedProvider.createDownloadItem(0, "19840116 12:00"); + mDownloadDelegate.regularItems.add(item); + initializeAdapter(false); + checkAdapterContents(null, item); + Assert.assertEquals(1, mAdapter.getTotalDownloadSize()); + } + + /** Toggle the info button. Storage header should turn off/on accordingly. */ + @Test + @SmallTest + public void testToggleStorageHeader() throws Exception { + DownloadItem item0 = StubbedProvider.createDownloadItem(0, "19840116 12:00"); + DownloadItem item1 = StubbedProvider.createDownloadItem(1, "19840116 12:01"); + mDownloadDelegate.regularItems.add(item0); + mDownloadDelegate.regularItems.add(item1); + initializeAdapter(false); + checkAdapterContents(HEADER, null, item1, item0); + Assert.assertEquals(11, mAdapter.getTotalDownloadSize()); + + // Turn off info and check that header is gone. + ThreadUtils.runOnUiThreadBlocking(new Runnable() { + @Override + public void run() { + mAdapter.setShowStorageInfoHeader(false); + } + }); + checkAdapterContents(null, item1, item0); + + // Turn on info and check that header is back again. + ThreadUtils.runOnUiThreadBlocking(new Runnable() { + @Override + public void run() { + mAdapter.setShowStorageInfoHeader(true); + } + }); + checkAdapterContents(HEADER, null, item1, item0); + } + /** Off the record downloads are ignored if the DownloadHistoryAdapter isn't watching them. */ @Test @SmallTest
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/notifications/channels/ChannelsInitializerTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/notifications/channels/ChannelsInitializerTest.java new file mode 100644 index 0000000..db541ed --- /dev/null +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/notifications/channels/ChannelsInitializerTest.java
@@ -0,0 +1,250 @@ +// Copyright 2017 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.notifications.channels; + +import static org.hamcrest.Matchers.containsInAnyOrder; +import static org.hamcrest.Matchers.empty; +import static org.hamcrest.Matchers.hasSize; +import static org.hamcrest.Matchers.is; +import static org.hamcrest.Matchers.not; +import static org.junit.Assert.assertThat; + +import android.annotation.TargetApi; +import android.app.NotificationManager; +import android.content.Context; +import android.os.Build; +import android.support.test.InstrumentationRegistry; +import android.support.test.filters.SmallTest; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; + +import org.chromium.base.BuildInfo; +import org.chromium.base.test.BaseJUnit4ClassRunner; +import org.chromium.base.test.util.Feature; +import org.chromium.base.test.util.MinAndroidSdkLevel; +import org.chromium.chrome.browser.notifications.NotificationManagerProxy; +import org.chromium.chrome.browser.notifications.NotificationManagerProxyImpl; +import org.chromium.chrome.test.util.browser.notifications.MockNotificationManagerProxy; + +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; + +/** + * Instrumentation tests for ChannelsInitializer. + * + * These are Android instrumentation tests so that resource strings can be accessed, and so that + * we can test against the real NotificationManager implementation. + */ +@RunWith(BaseJUnit4ClassRunner.class) +public class ChannelsInitializerTest { + private static final String MISCELLANEOUS_CHANNEL_ID = "miscellaneous"; + private ChannelsInitializer mChannelsInitializer; + private NotificationManagerProxy mNotificationManagerProxy; + private Context mContext; + + @Before + public void setUp() throws Exception { + mContext = InstrumentationRegistry.getInstrumentation().getTargetContext(); + mNotificationManagerProxy = new NotificationManagerProxyImpl( + (NotificationManager) mContext.getSystemService(Context.NOTIFICATION_SERVICE)); + mChannelsInitializer = + new ChannelsInitializer(mNotificationManagerProxy, mContext.getResources()); + // Delete any channels that may already have been initialized. Cleaning up here rather than + // in tearDown in case tests running before these ones caused channels to be created. + for (String channelId : ChannelDefinitions.getStartupChannelIds()) { + mNotificationManagerProxy.deleteNotificationChannel(channelId); + } + } + + @Test + @SmallTest + // TODO(crbug.com/685808) Replace this with VERSION_CODES.O & remove isAtLeastO check below. + @MinAndroidSdkLevel(Build.VERSION_CODES.N_MR1) + @TargetApi(Build.VERSION_CODES.N_MR1) + @Feature({"Browser", "Notifications"}) + public void testDeleteLegacyChannels_noopOnCurrentDefinitions() throws Exception { + if (!BuildInfo.isAtLeastO()) return; + assertThat(getChannelsIgnoringMiscellaneous(), is(empty())); + + mChannelsInitializer.deleteLegacyChannels(); + assertThat(getChannelsIgnoringMiscellaneous(), is(empty())); + + mChannelsInitializer.initializeStartupChannels(); + assertThat(getChannelsIgnoringMiscellaneous(), is(not(empty()))); + + int nChannels = getChannelsIgnoringMiscellaneous().size(); + mChannelsInitializer.deleteLegacyChannels(); + assertThat(getChannelsIgnoringMiscellaneous(), hasSize(nChannels)); + } + + @Test + @SmallTest + // TODO(crbug.com/685808) Replace this with VERSION_CODES.O & remove isAtLeastO check below. + @MinAndroidSdkLevel(Build.VERSION_CODES.N_MR1) + @TargetApi(Build.VERSION_CODES.N_MR1) + @Feature({"Browser", "Notifications"}) + public void testInitializeStartupChannels() throws Exception { + if (!BuildInfo.isAtLeastO()) return; + mChannelsInitializer.initializeStartupChannels(); + List<String> notificationChannelIds = new ArrayList<>(); + for (Channel channel : getChannelsIgnoringMiscellaneous()) { + notificationChannelIds.add(channel.getId()); + } + assertThat(notificationChannelIds, + containsInAnyOrder(ChannelDefinitions.CHANNEL_ID_BROWSER, + ChannelDefinitions.CHANNEL_ID_DOWNLOADS, + ChannelDefinitions.CHANNEL_ID_INCOGNITO, + ChannelDefinitions.CHANNEL_ID_SITES, ChannelDefinitions.CHANNEL_ID_MEDIA)); + } + + @Test + @SmallTest + // TODO(crbug.com/685808) Replace this with VERSION_CODES.O & remove isAtLeastO check below. + @MinAndroidSdkLevel(Build.VERSION_CODES.N_MR1) + @TargetApi(Build.VERSION_CODES.N_MR1) + @Feature({"Browser", "Notifications"}) + public void testInitializeStartupChannels_groupCreated() throws Exception { + if (!BuildInfo.isAtLeastO()) return; + // Use a mock notification manager since the real one does not allow us to query which + // groups have been created. + MockNotificationManagerProxy mockNotificationManager = new MockNotificationManagerProxy(); + ChannelsInitializer channelsInitializer = + new ChannelsInitializer(mockNotificationManager, mContext.getResources()); + channelsInitializer.initializeStartupChannels(); + assertThat(mockNotificationManager.getNotificationChannelGroups(), hasSize(1)); + assertThat(mockNotificationManager.getNotificationChannelGroups().get(0).mId, + is(ChannelDefinitions.CHANNEL_GROUP_ID_GENERAL)); + } + + @Test + @SmallTest + // TODO(crbug.com/685808) Replace this with VERSION_CODES.O & remove isAtLeastO check below. + @MinAndroidSdkLevel(Build.VERSION_CODES.N_MR1) + @TargetApi(Build.VERSION_CODES.N_MR1) + @Feature({"Browser", "Notifications"}) + public void testEnsureInitialized_browserChannel() throws Exception { + if (!BuildInfo.isAtLeastO()) return; + mChannelsInitializer.ensureInitialized(ChannelDefinitions.CHANNEL_ID_BROWSER); + + assertThat(getChannelsIgnoringMiscellaneous(), hasSize(1)); + Channel channel = getChannelsIgnoringMiscellaneous().get(0); + assertThat(channel.getId(), is(ChannelDefinitions.CHANNEL_ID_BROWSER)); + assertThat(channel.getName().toString(), + is(mContext.getString(org.chromium.chrome.R.string.notification_category_browser))); + assertThat(channel.getImportance(), is(NotificationManager.IMPORTANCE_LOW)); + assertThat(channel.getGroupId(), is(ChannelDefinitions.CHANNEL_GROUP_ID_GENERAL)); + } + + @Test + @SmallTest + // TODO(crbug.com/685808) Replace this with VERSION_CODES.O & remove isAtLeastO check below. + @MinAndroidSdkLevel(Build.VERSION_CODES.N_MR1) + @TargetApi(Build.VERSION_CODES.N_MR1) + @Feature({"Browser", "Notifications"}) + public void testEnsureInitialized_downloadsChannel() throws Exception { + if (!BuildInfo.isAtLeastO()) return; + mChannelsInitializer.ensureInitialized(ChannelDefinitions.CHANNEL_ID_DOWNLOADS); + + assertThat(getChannelsIgnoringMiscellaneous(), hasSize(1)); + Channel channel = getChannelsIgnoringMiscellaneous().get(0); + assertThat(channel.getId(), is(ChannelDefinitions.CHANNEL_ID_DOWNLOADS)); + assertThat(channel.getName().toString(), + is(mContext.getString( + org.chromium.chrome.R.string.notification_category_downloads))); + assertThat(channel.getImportance(), is(NotificationManager.IMPORTANCE_LOW)); + assertThat(channel.getGroupId(), is(ChannelDefinitions.CHANNEL_GROUP_ID_GENERAL)); + } + + @Test + @SmallTest + // TODO(crbug.com/685808) Replace this with VERSION_CODES.O & remove isAtLeastO check below. + @MinAndroidSdkLevel(Build.VERSION_CODES.N_MR1) + @TargetApi(Build.VERSION_CODES.N_MR1) + @Feature({"Browser", "Notifications"}) + public void testEnsureInitialized_incognitoChannel() throws Exception { + if (!BuildInfo.isAtLeastO()) return; + mChannelsInitializer.ensureInitialized(ChannelDefinitions.CHANNEL_ID_INCOGNITO); + + assertThat(getChannelsIgnoringMiscellaneous(), hasSize(1)); + Channel channel = getChannelsIgnoringMiscellaneous().get(0); + assertThat(channel.getId(), is(ChannelDefinitions.CHANNEL_ID_INCOGNITO)); + assertThat(channel.getName().toString(), + is(mContext.getString( + org.chromium.chrome.R.string.notification_category_incognito))); + assertThat(channel.getImportance(), is(NotificationManager.IMPORTANCE_LOW)); + assertThat(channel.getGroupId(), is(ChannelDefinitions.CHANNEL_GROUP_ID_GENERAL)); + } + + @Test + @SmallTest + // TODO(crbug.com/685808) Replace this with VERSION_CODES.O & remove isAtLeastO check below. + @MinAndroidSdkLevel(Build.VERSION_CODES.N_MR1) + @TargetApi(Build.VERSION_CODES.N_MR1) + @Feature({"Browser", "Notifications"}) + public void testEnsureInitialized_mediaChannel() throws Exception { + if (!BuildInfo.isAtLeastO()) return; + mChannelsInitializer.ensureInitialized(ChannelDefinitions.CHANNEL_ID_MEDIA); + + assertThat(getChannelsIgnoringMiscellaneous(), hasSize(1)); + Channel channel = getChannelsIgnoringMiscellaneous().get(0); + assertThat(channel.getId(), is(ChannelDefinitions.CHANNEL_ID_MEDIA)); + assertThat(channel.getName().toString(), + is(mContext.getString(org.chromium.chrome.R.string.notification_category_media))); + assertThat(channel.getImportance(), is(NotificationManager.IMPORTANCE_LOW)); + assertThat(channel.getGroupId(), is(ChannelDefinitions.CHANNEL_GROUP_ID_GENERAL)); + } + + @Test + @SmallTest + // TODO(crbug.com/685808) Replace this with VERSION_CODES.O & remove isAtLeastO check below. + @MinAndroidSdkLevel(Build.VERSION_CODES.N_MR1) + @TargetApi(Build.VERSION_CODES.N_MR1) + @Feature({"Browser", "Notifications"}) + public void testEnsureInitialized_sitesChannel() throws Exception { + if (!BuildInfo.isAtLeastO()) return; + mChannelsInitializer.ensureInitialized(ChannelDefinitions.CHANNEL_ID_SITES); + + assertThat(getChannelsIgnoringMiscellaneous(), hasSize(1)); + + Channel channel = getChannelsIgnoringMiscellaneous().get(0); + assertThat(channel.getId(), is(ChannelDefinitions.CHANNEL_ID_SITES)); + assertThat(channel.getName().toString(), + is(mContext.getString(org.chromium.chrome.R.string.notification_category_sites))); + assertThat(channel.getImportance(), is(NotificationManager.IMPORTANCE_DEFAULT)); + assertThat(channel.getGroupId(), is(ChannelDefinitions.CHANNEL_GROUP_ID_GENERAL)); + } + + @Test + @SmallTest + // TODO(crbug.com/685808) Replace this with VERSION_CODES.O & remove isAtLeastO check below. + @MinAndroidSdkLevel(Build.VERSION_CODES.N_MR1) + @TargetApi(Build.VERSION_CODES.N_MR1) + @Feature({"Browser", "Notifications"}) + public void testEnsureInitialized_multipleCalls() throws Exception { + if (!BuildInfo.isAtLeastO()) return; + mChannelsInitializer.ensureInitialized(ChannelDefinitions.CHANNEL_ID_SITES); + mChannelsInitializer.ensureInitialized(ChannelDefinitions.CHANNEL_ID_BROWSER); + assertThat(getChannelsIgnoringMiscellaneous(), hasSize(2)); + } + + /** + * Gets the current notification channels from the notification manager, except for any with + * the id 'miscellaneous', which will be removed from the list before returning. + * + * (Android *might* add a Miscellaneous channel on our behalf, but we don't want to tie our + * tests to its presence, as this could change). + */ + private List<Channel> getChannelsIgnoringMiscellaneous() { + List<Channel> channels = mNotificationManagerProxy.getNotificationChannels(); + for (Iterator<Channel> it = channels.iterator(); it.hasNext();) { + Channel channel = it.next(); + if (channel.getId().equals(MISCELLANEOUS_CHANNEL_ID)) it.remove(); + } + return channels; + } +} \ No newline at end of file
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/offlinepages/OfflinePageBridgeTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/offlinepages/OfflinePageBridgeTest.java index c6a6038..a45433d7 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/offlinepages/OfflinePageBridgeTest.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/offlinepages/OfflinePageBridgeTest.java
@@ -37,6 +37,7 @@ import java.util.concurrent.Semaphore; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicInteger; +import java.util.concurrent.atomic.AtomicLong; import java.util.concurrent.atomic.AtomicReference; /** Unit tests for {@link OfflinePageBridge}. */ @@ -283,9 +284,93 @@ Assert.assertEquals(requests[0].getUrl(), remaining[0].getUrl()); } - private void savePage(final int expectedResult, final String expectedUrl) + @Test + @SmallTest + public void testDeletePagesByOfflineIds() throws Exception { + // Save 3 pages and record their offline IDs to delete later. + Set<String> pageUrls = new HashSet<>(); + pageUrls.add(mTestPage); + pageUrls.add(mTestPage + "?foo=1"); + pageUrls.add(mTestPage + "?foo=2"); + int pagesToDeleteCount = pageUrls.size(); + List<Long> offlineIdsToDelete = new ArrayList<>(); + for (String url : pageUrls) { + mActivityTestRule.loadUrl(url); + offlineIdsToDelete.add(savePage(SavePageResult.SUCCESS, url)); + } + Assert.assertEquals("The pages should exist now that we saved them.", pagesToDeleteCount, + checkPagesExistOffline(pageUrls).size()); + + // Save one more page but don't save the offline ID, this page should not be deleted. + Set<String> pageUrlsToSave = new HashSet<>(); + String pageToSave = mTestPage + "?bar=1"; + pageUrlsToSave.add(pageToSave); + int pagesToSaveCount = pageUrlsToSave.size(); + for (String url : pageUrlsToSave) { + mActivityTestRule.loadUrl(url); + savePage(SavePageResult.SUCCESS, pageToSave); + } + Assert.assertEquals("The pages should exist now that we saved them.", pagesToSaveCount, + checkPagesExistOffline(pageUrlsToSave).size()); + + // Delete the first 3 pages. + deletePages(offlineIdsToDelete); + Assert.assertEquals( + "The page should cease to exist.", 0, checkPagesExistOffline(pageUrls).size()); + + // We should not have deleted the one we didn't ask to delete. + Assert.assertEquals("The page should not be deleted.", pagesToSaveCount, + checkPagesExistOffline(pageUrlsToSave).size()); + } + + @Test + @SmallTest + public void testGetPagesForNamespace() throws Exception { + // Save 3 pages and record their offline IDs to delete later. + Set<Long> offlineIdsToFetch = new HashSet<>(); + for (int i = 0; i < 3; i++) { + String url = mTestPage + "?foo=" + i; + mActivityTestRule.loadUrl(url); + offlineIdsToFetch.add(savePage(SavePageResult.SUCCESS, url)); + } + + // Save a page in a different namespace. + String urlToIgnore = mTestPage + "?bar=1"; + mActivityTestRule.loadUrl(urlToIgnore); + long offlineIdToIgnore = savePage(SavePageResult.SUCCESS, urlToIgnore, + new ClientId(OfflinePageBridge.ASYNC_NAMESPACE, "-42")); + + List<OfflinePageItem> pages = getPagesForNamespace(OfflinePageBridge.BOOKMARK_NAMESPACE); + Assert.assertEquals( + "The number of pages returned does not match the number of pages saved.", + offlineIdsToFetch.size(), pages.size()); + for (OfflinePageItem page : pages) { + offlineIdsToFetch.remove(page.getOfflineId()); + } + Assert.assertEquals( + "There were different pages saved than those returned by getPagesForNamespace.", 0, + offlineIdsToFetch.size()); + + // Check that the page in the other namespace still exists. + List<OfflinePageItem> asyncPages = getPagesForNamespace(OfflinePageBridge.ASYNC_NAMESPACE); + Assert.assertEquals("The page saved in an alternate namespace is no longer there.", 1, + asyncPages.size()); + Assert.assertEquals( + "The offline ID of the page saved in an alternate namespace does not match.", + offlineIdToIgnore, asyncPages.get(0).getOfflineId()); + } + + // Returns offline ID. + private long savePage(final int expectedResult, final String expectedUrl) throws InterruptedException { + return savePage(expectedResult, expectedUrl, BOOKMARK_ID); + } + + // Returns offline ID. + private long savePage(final int expectedResult, final String expectedUrl, + final ClientId clientId) throws InterruptedException { final Semaphore semaphore = new Semaphore(0); + final AtomicLong result = new AtomicLong(-1); ThreadUtils.runOnUiThreadBlocking(new Runnable() { @Override public void run() { @@ -297,8 +382,8 @@ mActivityTestRule.getActivity().getActivityTab().getWebContents()); mOfflinePageBridge.savePage( - mActivityTestRule.getActivity().getActivityTab().getWebContents(), - BOOKMARK_ID, new SavePageCallback() { + mActivityTestRule.getActivity().getActivityTab().getWebContents(), clientId, + new SavePageCallback() { @Override public void onSavePageDone( int savePageResult, String url, long offlineId) { @@ -306,12 +391,30 @@ "Requested and returned URLs differ.", expectedUrl, url); Assert.assertEquals( "Save result incorrect.", expectedResult, savePageResult); + result.set(offlineId); semaphore.release(); } }); } }); Assert.assertTrue(semaphore.tryAcquire(TIMEOUT_MS, TimeUnit.MILLISECONDS)); + return result.get(); + } + + private void deletePages(final List<Long> offlineIds) throws InterruptedException { + final Semaphore semaphore = new Semaphore(0); + ThreadUtils.runOnUiThread(new Runnable() { + @Override + public void run() { + mOfflinePageBridge.deletePagesByOfflineId(offlineIds, new Callback<Integer>() { + @Override + public void onResult(Integer deletePageResult) { + semaphore.release(); + } + }); + } + }); + Assert.assertTrue(semaphore.tryAcquire(TIMEOUT_MS, TimeUnit.MILLISECONDS)); } private void deletePage(final ClientId bookmarkId, final int expectedResult) @@ -353,6 +456,27 @@ return result; } + private List<OfflinePageItem> getPagesForNamespace(final String namespace) + throws InterruptedException { + final List<OfflinePageItem> result = new ArrayList<OfflinePageItem>(); + final Semaphore semaphore = new Semaphore(0); + ThreadUtils.runOnUiThread(new Runnable() { + @Override + public void run() { + mOfflinePageBridge.getPagesForNamespace( + namespace, new Callback<List<OfflinePageItem>>() { + @Override + public void onResult(List<OfflinePageItem> pages) { + result.addAll(pages); + semaphore.release(); + } + }); + } + }); + Assert.assertTrue(semaphore.tryAcquire(TIMEOUT_MS, TimeUnit.MILLISECONDS)); + return result; + } + private void forceConnectivityStateOnUiThread(final boolean state) { ThreadUtils.runOnUiThreadBlocking(new Runnable() { @Override
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestAbortTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestAbortTest.java index 33fee62..13ebc38f8 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestAbortTest.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestAbortTest.java
@@ -6,11 +6,20 @@ import android.support.test.filters.MediumTest; +import org.junit.Rule; +import org.junit.Test; +import org.junit.runner.RunWith; + +import org.chromium.base.test.util.CommandLineFlags; import org.chromium.base.test.util.Feature; import org.chromium.chrome.R; +import org.chromium.chrome.browser.ChromeSwitches; import org.chromium.chrome.browser.autofill.AutofillTestHelper; import org.chromium.chrome.browser.autofill.PersonalDataManager.AutofillProfile; import org.chromium.chrome.browser.autofill.PersonalDataManager.CreditCard; +import org.chromium.chrome.browser.payments.PaymentRequestTestRule.MainActivityStartCallback; +import org.chromium.chrome.test.ChromeActivityTestRule; +import org.chromium.chrome.test.ChromeJUnit4ClassRunner; import java.util.concurrent.ExecutionException; import java.util.concurrent.TimeoutException; @@ -18,11 +27,15 @@ /** * A payment integration test for a merchant that aborts their payment request. */ -public class PaymentRequestAbortTest extends PaymentRequestTestBase { - public PaymentRequestAbortTest() { - // This merchant aborts the payment request when the "abort" button is clicked. - super("payment_request_abort_test.html"); - } +@RunWith(ChromeJUnit4ClassRunner.class) +@CommandLineFlags.Add({ + ChromeSwitches.DISABLE_FIRST_RUN_EXPERIENCE, + ChromeActivityTestRule.DISABLE_NETWORK_PREDICTION_FLAG, +}) +public class PaymentRequestAbortTest implements MainActivityStartCallback { + @Rule + public PaymentRequestTestRule mPaymentRequestTestRule = + new PaymentRequestTestRule("payment_request_abort_test.html", this); @Override public void onMainActivityStarted() @@ -37,23 +50,27 @@ } /** If the user has not clicked "Pay" yet, then merchant's abort will succeed. */ + @Test @MediumTest @Feature({"Payments"}) - public void testAbortBeforePayClicked() throws InterruptedException, ExecutionException, - TimeoutException { - triggerUIAndWait(getReadyToPay()); - clickNodeAndWait("abort", getDismissed()); - expectResultContains(new String[] {"Aborted"}); + public void testAbortBeforePayClicked() + throws InterruptedException, ExecutionException, TimeoutException { + mPaymentRequestTestRule.triggerUIAndWait(mPaymentRequestTestRule.getReadyToPay()); + mPaymentRequestTestRule.clickNodeAndWait("abort", mPaymentRequestTestRule.getDismissed()); + mPaymentRequestTestRule.expectResultContains(new String[] {"Aborted"}); } /** If the user has already clicked the "Pay" button, then merchant won't be able to abort. */ + @Test @MediumTest @Feature({"Payments"}) - public void testAbortWhileUnmaskingCard() throws InterruptedException, ExecutionException, - TimeoutException { - triggerUIAndWait(getReadyToPay()); - clickAndWait(R.id.button_primary, getReadyForUnmaskInput()); - clickNodeAndWait("abort", getUnableToAbort()); - expectResultContains(new String[] {"Cannot abort"}); + public void testAbortWhileUnmaskingCard() + throws InterruptedException, ExecutionException, TimeoutException { + mPaymentRequestTestRule.triggerUIAndWait(mPaymentRequestTestRule.getReadyToPay()); + mPaymentRequestTestRule.clickAndWait( + R.id.button_primary, mPaymentRequestTestRule.getReadyForUnmaskInput()); + mPaymentRequestTestRule.clickNodeAndWait( + "abort", mPaymentRequestTestRule.getUnableToAbort()); + mPaymentRequestTestRule.expectResultContains(new String[] {"Cannot abort"}); } }
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestBillingAddressTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestBillingAddressTest.java index 70db97b9..d5e3226 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestBillingAddressTest.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestBillingAddressTest.java
@@ -4,13 +4,27 @@ package org.chromium.chrome.browser.payments; +import static org.chromium.chrome.browser.payments.PaymentRequestTestRule.DECEMBER; +import static org.chromium.chrome.browser.payments.PaymentRequestTestRule.FIRST_BILLING_ADDRESS; +import static org.chromium.chrome.browser.payments.PaymentRequestTestRule.NEXT_YEAR; + import android.support.test.filters.MediumTest; +import org.junit.Assert; +import org.junit.Rule; +import org.junit.Test; +import org.junit.runner.RunWith; + +import org.chromium.base.test.util.CommandLineFlags; import org.chromium.base.test.util.Feature; import org.chromium.chrome.R; +import org.chromium.chrome.browser.ChromeSwitches; import org.chromium.chrome.browser.autofill.AutofillTestHelper; import org.chromium.chrome.browser.autofill.PersonalDataManager.AutofillProfile; import org.chromium.chrome.browser.autofill.PersonalDataManager.CreditCard; +import org.chromium.chrome.browser.payments.PaymentRequestTestRule.MainActivityStartCallback; +import org.chromium.chrome.test.ChromeActivityTestRule; +import org.chromium.chrome.test.ChromeJUnit4ClassRunner; import java.util.concurrent.ExecutionException; import java.util.concurrent.TimeoutException; @@ -18,8 +32,17 @@ /** * A payment integration test for biling addresses. */ -public class PaymentRequestBillingAddressTest extends PaymentRequestTestBase { - /* +@RunWith(ChromeJUnit4ClassRunner.class) +@CommandLineFlags.Add({ + ChromeSwitches.DISABLE_FIRST_RUN_EXPERIENCE, + ChromeActivityTestRule.DISABLE_NETWORK_PREDICTION_FLAG, +}) +public class PaymentRequestBillingAddressTest implements MainActivityStartCallback { + @Rule + public PaymentRequestTestRule mPaymentRequestTestRule = + new PaymentRequestTestRule("payment_request_free_shipping_test.html", this); + + /** * The index at which the option to add a billing address is located in the billing address * selection dropdown. */ @@ -28,10 +51,6 @@ /** The index of the billing address dropdown in the card editor. */ private static final int BILLING_ADDRESS_DROPDOWN_INDEX = 2; - public PaymentRequestBillingAddressTest() { - super("payment_request_free_shipping_test.html"); - } - @Override public void onMainActivityStarted() throws InterruptedException, ExecutionException, TimeoutException { @@ -92,287 +111,395 @@ } /** Verifies the format of the billing address suggestions when adding a new credit card. */ + @Test @MediumTest @Feature({"Payments"}) public void testNewCardBillingAddressFormat() throws InterruptedException, ExecutionException, TimeoutException { - triggerUIAndWait(getReadyToPay()); - clickInPaymentMethodAndWait(R.id.payments_section, getReadyForInput()); - clickInPaymentMethodAndWait(R.id.payments_add_option_button, getReadyToEdit()); - setTextInCardEditorAndWait( - new String[] {"5454-5454-5454-5454", "Bob"}, getEditorTextUpdate()); - setSpinnerSelectionsInCardEditorAndWait( + mPaymentRequestTestRule.triggerUIAndWait(mPaymentRequestTestRule.getReadyToPay()); + mPaymentRequestTestRule.clickInPaymentMethodAndWait( + R.id.payments_section, mPaymentRequestTestRule.getReadyForInput()); + mPaymentRequestTestRule.clickInPaymentMethodAndWait( + R.id.payments_add_option_button, mPaymentRequestTestRule.getReadyToEdit()); + mPaymentRequestTestRule.setTextInCardEditorAndWait( + new String[] {"5454-5454-5454-5454", "Bob"}, + mPaymentRequestTestRule.getEditorTextUpdate()); + mPaymentRequestTestRule.setSpinnerSelectionsInCardEditorAndWait( new int[] {DECEMBER, NEXT_YEAR, FIRST_BILLING_ADDRESS}, - getBillingAddressChangeProcessed()); + mPaymentRequestTestRule.getBillingAddressChangeProcessed()); // The billing address suggestions should include only the name, address, city, state and // zip code of the profile. - assertTrue(getSpinnerSelectionTextInCardEditor(BILLING_ADDRESS_DROPDOWN_INDEX) - .equals("Rob Doe, 340 Main St, Los Angeles, CA 90291")); + Assert.assertTrue( + mPaymentRequestTestRule + .getSpinnerSelectionTextInCardEditor(BILLING_ADDRESS_DROPDOWN_INDEX) + .equals("Rob Doe, 340 Main St, Los Angeles, CA 90291")); } /** * Verifies that the correct number of billing address suggestions are shown when adding a new * credit card. */ + @Test @MediumTest @Feature({"Payments"}) public void testNumberOfBillingAddressSuggestions() throws InterruptedException, ExecutionException, TimeoutException { - triggerUIAndWait(getReadyToPay()); - clickInPaymentMethodAndWait(R.id.payments_section, getReadyForInput()); - clickInPaymentMethodAndWait(R.id.payments_add_option_button, getReadyToEdit()); + mPaymentRequestTestRule.triggerUIAndWait(mPaymentRequestTestRule.getReadyToPay()); + mPaymentRequestTestRule.clickInPaymentMethodAndWait( + R.id.payments_section, mPaymentRequestTestRule.getReadyForInput()); + mPaymentRequestTestRule.clickInPaymentMethodAndWait( + R.id.payments_add_option_button, mPaymentRequestTestRule.getReadyToEdit()); // There should only be 8 suggestions, the 7 saved addresses and the option to add a new // address. - assertEquals(8, getSpinnerItemCountInCardEditor(BILLING_ADDRESS_DROPDOWN_INDEX)); + Assert.assertEquals(8, + mPaymentRequestTestRule.getSpinnerItemCountInCardEditor( + BILLING_ADDRESS_DROPDOWN_INDEX)); } /** * Verifies that the correct number of billing address suggestions are shown when adding a new * credit card, even after cancelling out of adding a new billing address. */ + @Test @MediumTest @Feature({"Payments"}) public void testNumberOfBillingAddressSuggestions_AfterCancellingNewBillingAddress() throws InterruptedException, ExecutionException, TimeoutException { // Add a payment method and add a new billing address. - triggerUIAndWait(getReadyToPay()); - clickInPaymentMethodAndWait(R.id.payments_section, getReadyForInput()); - clickInPaymentMethodAndWait(R.id.payments_add_option_button, getReadyToEdit()); + mPaymentRequestTestRule.triggerUIAndWait(mPaymentRequestTestRule.getReadyToPay()); + mPaymentRequestTestRule.clickInPaymentMethodAndWait( + R.id.payments_section, mPaymentRequestTestRule.getReadyForInput()); + mPaymentRequestTestRule.clickInPaymentMethodAndWait( + R.id.payments_add_option_button, mPaymentRequestTestRule.getReadyToEdit()); // Select the "+ ADD ADDRESS" option for the billing address. - setSpinnerSelectionsInCardEditorAndWait( - new int[] {DECEMBER, NEXT_YEAR, ADD_BILLING_ADDRESS}, getReadyToEdit()); + mPaymentRequestTestRule.setSpinnerSelectionsInCardEditorAndWait( + new int[] {DECEMBER, NEXT_YEAR, ADD_BILLING_ADDRESS}, + mPaymentRequestTestRule.getReadyToEdit()); // Cancel the creation of a new billing address. - clickInEditorAndWait(R.id.payments_edit_cancel_button, getReadyToEdit()); + mPaymentRequestTestRule.clickInEditorAndWait( + R.id.payments_edit_cancel_button, mPaymentRequestTestRule.getReadyToEdit()); // There should still only be 8 suggestions, the 7 saved addresses and the option to add a // new address. - assertEquals(8, getSpinnerItemCountInCardEditor(BILLING_ADDRESS_DROPDOWN_INDEX)); + Assert.assertEquals(8, + mPaymentRequestTestRule.getSpinnerItemCountInCardEditor( + BILLING_ADDRESS_DROPDOWN_INDEX)); } /** * Tests that for a card that already has a billing address, adding a new one and cancelling * maintains the previous selection. */ + @Test @MediumTest @Feature({"Payments"}) public void testAddBillingAddressOnCardAndCancel_MaintainsPreviousSelection() throws InterruptedException, ExecutionException, TimeoutException { - triggerUIAndWait(getReadyToPay()); + mPaymentRequestTestRule.triggerUIAndWait(mPaymentRequestTestRule.getReadyToPay()); // Edit the only card. - clickInPaymentMethodAndWait(R.id.payments_section, getReadyForInput()); - clickInPaymentMethodAndWait(R.id.payments_open_editor_pencil_button, getReadyToEdit()); + mPaymentRequestTestRule.clickInPaymentMethodAndWait( + R.id.payments_section, mPaymentRequestTestRule.getReadyForInput()); + mPaymentRequestTestRule.clickInPaymentMethodAndWait( + R.id.payments_open_editor_pencil_button, mPaymentRequestTestRule.getReadyToEdit()); // Jon Doe is selected as the billing address. - assertTrue(getSpinnerSelectionTextInCardEditor(BILLING_ADDRESS_DROPDOWN_INDEX) - .equals("Jon Doe, 340 Main St, Los Angeles, CA 90291")); + Assert.assertTrue( + mPaymentRequestTestRule + .getSpinnerSelectionTextInCardEditor(BILLING_ADDRESS_DROPDOWN_INDEX) + .equals("Jon Doe, 340 Main St, Los Angeles, CA 90291")); // Select the "+ ADD ADDRESS" option for the billing address. - setSpinnerSelectionsInCardEditorAndWait( - new int[] {DECEMBER, NEXT_YEAR, ADD_BILLING_ADDRESS}, getReadyToEdit()); + mPaymentRequestTestRule.setSpinnerSelectionsInCardEditorAndWait( + new int[] {DECEMBER, NEXT_YEAR, ADD_BILLING_ADDRESS}, + mPaymentRequestTestRule.getReadyToEdit()); // Cancel the creation of a new billing address. - clickInEditorAndWait(R.id.payments_edit_cancel_button, getReadyToEdit()); + mPaymentRequestTestRule.clickInEditorAndWait( + R.id.payments_edit_cancel_button, mPaymentRequestTestRule.getReadyToEdit()); // Jon Doe is STILL selected as the billing address. - assertTrue(getSpinnerSelectionTextInCardEditor(BILLING_ADDRESS_DROPDOWN_INDEX) - .equals("Jon Doe, 340 Main St, Los Angeles, CA 90291")); + Assert.assertTrue( + mPaymentRequestTestRule + .getSpinnerSelectionTextInCardEditor(BILLING_ADDRESS_DROPDOWN_INDEX) + .equals("Jon Doe, 340 Main St, Los Angeles, CA 90291")); } /** * Tests that adding a billing address for a card that has none, and cancelling then returns * to the proper selection (Select...). */ + @Test @MediumTest @Feature({"Payments"}) public void testAddBillingAddressOnCardWithNoBillingAndCancel_MaintainsPreviousSelection() throws InterruptedException, ExecutionException, TimeoutException { - triggerUIAndWait(getReadyToPay()); + mPaymentRequestTestRule.triggerUIAndWait(mPaymentRequestTestRule.getReadyToPay()); // Edit the second card. - clickInPaymentMethodAndWait(R.id.payments_section, getReadyForInput()); - clickOnPaymentMethodSuggestionOptionAndWait(1, getReadyToEdit()); + mPaymentRequestTestRule.clickInPaymentMethodAndWait( + R.id.payments_section, mPaymentRequestTestRule.getReadyForInput()); + mPaymentRequestTestRule.clickOnPaymentMethodSuggestionOptionAndWait( + 1, mPaymentRequestTestRule.getReadyToEdit()); // Now in Card Editor to add a billing address. "Select" is selected in the dropdown. - assertTrue(getSpinnerSelectionTextInCardEditor(BILLING_ADDRESS_DROPDOWN_INDEX) - .equals("Select")); + Assert.assertTrue( + mPaymentRequestTestRule + .getSpinnerSelectionTextInCardEditor(BILLING_ADDRESS_DROPDOWN_INDEX) + .equals("Select")); // Select the "+ ADD ADDRESS" option for the billing address. - setSpinnerSelectionsInCardEditorAndWait( - new int[] {DECEMBER, NEXT_YEAR, ADD_BILLING_ADDRESS}, getReadyToEdit()); + mPaymentRequestTestRule.setSpinnerSelectionsInCardEditorAndWait( + new int[] {DECEMBER, NEXT_YEAR, ADD_BILLING_ADDRESS}, + mPaymentRequestTestRule.getReadyToEdit()); // Cancel the creation of a new billing address. - clickInEditorAndWait(R.id.payments_edit_cancel_button, getReadyToEdit()); + mPaymentRequestTestRule.clickInEditorAndWait( + R.id.payments_edit_cancel_button, mPaymentRequestTestRule.getReadyToEdit()); // "Select" is STILL selected as the billing address. - assertTrue(getSpinnerSelectionTextInCardEditor(BILLING_ADDRESS_DROPDOWN_INDEX) - .equals("Select")); + Assert.assertTrue( + mPaymentRequestTestRule + .getSpinnerSelectionTextInCardEditor(BILLING_ADDRESS_DROPDOWN_INDEX) + .equals("Select")); } /** * Verifies that the billing address suggestions are ordered by frecency. */ + @Test @MediumTest @Feature({"Payments"}) public void testBillingAddressSortedByFrecency() throws InterruptedException, ExecutionException, TimeoutException { // Add a payment method. - triggerUIAndWait(getReadyToPay()); - clickInPaymentMethodAndWait(R.id.payments_section, getReadyForInput()); - clickInPaymentMethodAndWait(R.id.payments_add_option_button, getReadyToEdit()); + mPaymentRequestTestRule.triggerUIAndWait(mPaymentRequestTestRule.getReadyToPay()); + mPaymentRequestTestRule.clickInPaymentMethodAndWait( + R.id.payments_section, mPaymentRequestTestRule.getReadyForInput()); + mPaymentRequestTestRule.clickInPaymentMethodAndWait( + R.id.payments_add_option_button, mPaymentRequestTestRule.getReadyToEdit()); // There should be 8 suggestions, the 7 saved addresses and the option to add a new address. - assertEquals(8, getSpinnerItemCountInCardEditor(BILLING_ADDRESS_DROPDOWN_INDEX)); + Assert.assertEquals(8, + mPaymentRequestTestRule.getSpinnerItemCountInCardEditor( + BILLING_ADDRESS_DROPDOWN_INDEX)); // The billing address suggestions should be ordered by frecency. - assertTrue(getSpinnerTextAtPositionInCardEditor(BILLING_ADDRESS_DROPDOWN_INDEX, - 0).equals("Rob Doe, 340 Main St, Los Angeles, CA 90291")); - assertTrue(getSpinnerTextAtPositionInCardEditor(BILLING_ADDRESS_DROPDOWN_INDEX, - 1).equals("Jon Doe, 340 Main St, Los Angeles, CA 90291")); - assertTrue(getSpinnerTextAtPositionInCardEditor(BILLING_ADDRESS_DROPDOWN_INDEX, - 2).equals("Tom Doe, 340 Main St, Los Angeles, CA 90291")); - assertTrue(getSpinnerTextAtPositionInCardEditor(BILLING_ADDRESS_DROPDOWN_INDEX, - 7).equals("Add address")); + Assert.assertTrue( + mPaymentRequestTestRule + .getSpinnerTextAtPositionInCardEditor(BILLING_ADDRESS_DROPDOWN_INDEX, 0) + .equals("Rob Doe, 340 Main St, Los Angeles, CA 90291")); + Assert.assertTrue( + mPaymentRequestTestRule + .getSpinnerTextAtPositionInCardEditor(BILLING_ADDRESS_DROPDOWN_INDEX, 1) + .equals("Jon Doe, 340 Main St, Los Angeles, CA 90291")); + Assert.assertTrue( + mPaymentRequestTestRule + .getSpinnerTextAtPositionInCardEditor(BILLING_ADDRESS_DROPDOWN_INDEX, 2) + .equals("Tom Doe, 340 Main St, Los Angeles, CA 90291")); + Assert.assertTrue( + mPaymentRequestTestRule + .getSpinnerTextAtPositionInCardEditor(BILLING_ADDRESS_DROPDOWN_INDEX, 7) + .equals("Add address")); } /** * Verifies that the billing address suggestions are ordered by frecency, except for a newly * created address which should be suggested first. */ + @Test @MediumTest @Feature({"Payments"}) public void testBillingAddressSortedByFrecency_AddNewAddress() throws InterruptedException, ExecutionException, TimeoutException { // Add a payment method. - triggerUIAndWait(getReadyToPay()); - clickInPaymentMethodAndWait(R.id.payments_section, getReadyForInput()); - clickInPaymentMethodAndWait(R.id.payments_add_option_button, getReadyToEdit()); + mPaymentRequestTestRule.triggerUIAndWait(mPaymentRequestTestRule.getReadyToPay()); + mPaymentRequestTestRule.clickInPaymentMethodAndWait( + R.id.payments_section, mPaymentRequestTestRule.getReadyForInput()); + mPaymentRequestTestRule.clickInPaymentMethodAndWait( + R.id.payments_add_option_button, mPaymentRequestTestRule.getReadyToEdit()); // Add a new billing address. - setSpinnerSelectionsInCardEditorAndWait( - new int[] {DECEMBER, NEXT_YEAR, ADD_BILLING_ADDRESS}, getReadyToEdit()); - setTextInEditorAndWait(new String[] { - "Seb Doe", "Google", "340 Main St", "Los Angeles", "CA", "90291", - "650-253-0000"}, - getEditorTextUpdate()); - clickInEditorAndWait(R.id.payments_edit_done_button, getReadyToEdit()); + mPaymentRequestTestRule.setSpinnerSelectionsInCardEditorAndWait( + new int[] {DECEMBER, NEXT_YEAR, ADD_BILLING_ADDRESS}, + mPaymentRequestTestRule.getReadyToEdit()); + mPaymentRequestTestRule.setTextInEditorAndWait( + new String[] {"Seb Doe", "Google", "340 Main St", "Los Angeles", "CA", "90291", + "650-253-0000"}, + mPaymentRequestTestRule.getEditorTextUpdate()); + mPaymentRequestTestRule.clickInEditorAndWait( + R.id.payments_edit_done_button, mPaymentRequestTestRule.getReadyToEdit()); // There should be 9 suggestions, the 7 initial addresses, the newly added address and the // option to add a new address. - assertEquals(9, getSpinnerItemCountInCardEditor(BILLING_ADDRESS_DROPDOWN_INDEX)); + Assert.assertEquals(9, + mPaymentRequestTestRule.getSpinnerItemCountInCardEditor( + BILLING_ADDRESS_DROPDOWN_INDEX)); // The fist suggestion should be the newly added address. - assertTrue(getSpinnerTextAtPositionInCardEditor(BILLING_ADDRESS_DROPDOWN_INDEX, - 0).equals("Seb Doe, 340 Main St, Los Angeles, CA 90291")); + Assert.assertTrue( + mPaymentRequestTestRule + .getSpinnerTextAtPositionInCardEditor(BILLING_ADDRESS_DROPDOWN_INDEX, 0) + .equals("Seb Doe, 340 Main St, Los Angeles, CA 90291")); // The rest of the billing address suggestions should be ordered by frecency. - assertTrue(getSpinnerTextAtPositionInCardEditor(BILLING_ADDRESS_DROPDOWN_INDEX, - 1).equals("Rob Doe, 340 Main St, Los Angeles, CA 90291")); - assertTrue(getSpinnerTextAtPositionInCardEditor(BILLING_ADDRESS_DROPDOWN_INDEX, - 2).equals("Jon Doe, 340 Main St, Los Angeles, CA 90291")); - assertTrue(getSpinnerTextAtPositionInCardEditor(BILLING_ADDRESS_DROPDOWN_INDEX, - 3).equals("Tom Doe, 340 Main St, Los Angeles, CA 90291")); - assertTrue(getSpinnerTextAtPositionInCardEditor(BILLING_ADDRESS_DROPDOWN_INDEX, - 8).equals("Add address")); + Assert.assertTrue( + mPaymentRequestTestRule + .getSpinnerTextAtPositionInCardEditor(BILLING_ADDRESS_DROPDOWN_INDEX, 1) + .equals("Rob Doe, 340 Main St, Los Angeles, CA 90291")); + Assert.assertTrue( + mPaymentRequestTestRule + .getSpinnerTextAtPositionInCardEditor(BILLING_ADDRESS_DROPDOWN_INDEX, 2) + .equals("Jon Doe, 340 Main St, Los Angeles, CA 90291")); + Assert.assertTrue( + mPaymentRequestTestRule + .getSpinnerTextAtPositionInCardEditor(BILLING_ADDRESS_DROPDOWN_INDEX, 3) + .equals("Tom Doe, 340 Main St, Los Angeles, CA 90291")); + Assert.assertTrue( + mPaymentRequestTestRule + .getSpinnerTextAtPositionInCardEditor(BILLING_ADDRESS_DROPDOWN_INDEX, 8) + .equals("Add address")); } /** * Verifies that a newly created shipping address is offered as the first billing address * suggestion. */ + @Test @MediumTest @Feature({"Payments"}) public void testNewShippingAddressSuggestedFirst() throws InterruptedException, ExecutionException, TimeoutException { - triggerUIAndWait(getReadyToPay()); + mPaymentRequestTestRule.triggerUIAndWait(mPaymentRequestTestRule.getReadyToPay()); // Add a shipping address. - clickInShippingSummaryAndWait(R.id.payments_section, getReadyForInput()); - clickInShippingAddressAndWait(R.id.payments_add_option_button, getReadyToEdit()); - setTextInEditorAndWait(new String[] {"Seb Doe", "Google", "340 Main St", "Los Angeles", - "CA", "90291", "650-253-0000"}, - getEditorTextUpdate()); - clickInEditorAndWait(R.id.payments_edit_done_button, getReadyToPay()); + mPaymentRequestTestRule.clickInShippingSummaryAndWait( + R.id.payments_section, mPaymentRequestTestRule.getReadyForInput()); + mPaymentRequestTestRule.clickInShippingAddressAndWait( + R.id.payments_add_option_button, mPaymentRequestTestRule.getReadyToEdit()); + mPaymentRequestTestRule.setTextInEditorAndWait( + new String[] {"Seb Doe", "Google", "340 Main St", "Los Angeles", "CA", "90291", + "650-253-0000"}, + mPaymentRequestTestRule.getEditorTextUpdate()); + mPaymentRequestTestRule.clickInEditorAndWait( + R.id.payments_edit_done_button, mPaymentRequestTestRule.getReadyToPay()); // Navigate to the card editor UI. - clickInPaymentMethodAndWait(R.id.payments_section, getReadyForInput()); - clickInPaymentMethodAndWait(R.id.payments_add_option_button, getReadyToEdit()); + mPaymentRequestTestRule.clickInPaymentMethodAndWait( + R.id.payments_section, mPaymentRequestTestRule.getReadyForInput()); + mPaymentRequestTestRule.clickInPaymentMethodAndWait( + R.id.payments_add_option_button, mPaymentRequestTestRule.getReadyToEdit()); // There should be 9 suggestions, the 7 initial addresses, the newly added address and the // option to add a new address. - assertEquals(9, getSpinnerItemCountInCardEditor(BILLING_ADDRESS_DROPDOWN_INDEX)); + Assert.assertEquals(9, + mPaymentRequestTestRule.getSpinnerItemCountInCardEditor( + BILLING_ADDRESS_DROPDOWN_INDEX)); // The new address should be suggested first. - assertTrue(getSpinnerTextAtPositionInCardEditor(BILLING_ADDRESS_DROPDOWN_INDEX, - 0).equals("Seb Doe, 340 Main St, Los Angeles, CA 90291")); + Assert.assertTrue( + mPaymentRequestTestRule + .getSpinnerTextAtPositionInCardEditor(BILLING_ADDRESS_DROPDOWN_INDEX, 0) + .equals("Seb Doe, 340 Main St, Los Angeles, CA 90291")); } + @Test @MediumTest @Feature({"Payments"}) public void testSelectIncompleteBillingAddress_EditComplete() throws InterruptedException, ExecutionException, TimeoutException { - triggerUIAndWait(getReadyToPay()); + mPaymentRequestTestRule.triggerUIAndWait(mPaymentRequestTestRule.getReadyToPay()); // Edit the second card. - clickInPaymentMethodAndWait(R.id.payments_section, getReadyForInput()); - clickOnPaymentMethodSuggestionOptionAndWait(1, getReadyToEdit()); + mPaymentRequestTestRule.clickInPaymentMethodAndWait( + R.id.payments_section, mPaymentRequestTestRule.getReadyForInput()); + mPaymentRequestTestRule.clickOnPaymentMethodSuggestionOptionAndWait( + 1, mPaymentRequestTestRule.getReadyToEdit()); // Now "Select" is selected in the dropdown. - assertTrue(getSpinnerSelectionTextInCardEditor(BILLING_ADDRESS_DROPDOWN_INDEX) - .equals("Select")); + Assert.assertTrue( + mPaymentRequestTestRule + .getSpinnerSelectionTextInCardEditor(BILLING_ADDRESS_DROPDOWN_INDEX) + .equals("Select")); // The incomplete addresses in the dropdown contain edit required messages. - assertTrue(getSpinnerTextAtPositionInCardEditor(BILLING_ADDRESS_DROPDOWN_INDEX, 4) - .endsWith("Name required")); - assertTrue(getSpinnerTextAtPositionInCardEditor(BILLING_ADDRESS_DROPDOWN_INDEX, - 5).endsWith("More information required")); - assertTrue(getSpinnerTextAtPositionInCardEditor(BILLING_ADDRESS_DROPDOWN_INDEX, 6) - .endsWith("Enter a valid address")); + Assert.assertTrue( + mPaymentRequestTestRule + .getSpinnerTextAtPositionInCardEditor(BILLING_ADDRESS_DROPDOWN_INDEX, 4) + .endsWith("Name required")); + Assert.assertTrue( + mPaymentRequestTestRule + .getSpinnerTextAtPositionInCardEditor(BILLING_ADDRESS_DROPDOWN_INDEX, 5) + .endsWith("More information required")); + Assert.assertTrue( + mPaymentRequestTestRule + .getSpinnerTextAtPositionInCardEditor(BILLING_ADDRESS_DROPDOWN_INDEX, 6) + .endsWith("Enter a valid address")); // Selects the fourth billing addresss that misses recipient name brings up the address // editor. - setSpinnerSelectionsInCardEditorAndWait( - new int[] {DECEMBER, NEXT_YEAR, 4}, getReadyToEdit()); - setTextInEditorAndWait(new String[] {"Lisa Doh", "Google", "340 Main St", "Los Angeles", - "CA", "90291", "650-253-0000"}, - getEditorTextUpdate()); - clickInEditorAndWait(R.id.payments_edit_done_button, getReadyToEdit()); + mPaymentRequestTestRule.setSpinnerSelectionsInCardEditorAndWait( + new int[] {DECEMBER, NEXT_YEAR, 4}, mPaymentRequestTestRule.getReadyToEdit()); + mPaymentRequestTestRule.setTextInEditorAndWait( + new String[] {"Lisa Doh", "Google", "340 Main St", "Los Angeles", "CA", "90291", + "650-253-0000"}, + mPaymentRequestTestRule.getEditorTextUpdate()); + mPaymentRequestTestRule.clickInEditorAndWait( + R.id.payments_edit_done_button, mPaymentRequestTestRule.getReadyToEdit()); // The newly completed address must be selected and put at the top of the dropdown. - assertTrue(getSpinnerSelectionTextInCardEditor(BILLING_ADDRESS_DROPDOWN_INDEX) - .equals("Lisa Doh, 340 Main St, Los Angeles, CA 90291")); - assertTrue(getSpinnerTextAtPositionInCardEditor(BILLING_ADDRESS_DROPDOWN_INDEX, - 0).equals("Lisa Doh, 340 Main St, Los Angeles, CA 90291")); + Assert.assertTrue( + mPaymentRequestTestRule + .getSpinnerSelectionTextInCardEditor(BILLING_ADDRESS_DROPDOWN_INDEX) + .equals("Lisa Doh, 340 Main St, Los Angeles, CA 90291")); + Assert.assertTrue( + mPaymentRequestTestRule + .getSpinnerTextAtPositionInCardEditor(BILLING_ADDRESS_DROPDOWN_INDEX, 0) + .equals("Lisa Doh, 340 Main St, Los Angeles, CA 90291")); } + @Test @MediumTest @Feature({"Payments"}) public void testSelectIncompleteBillingAddress_EditCancel() throws InterruptedException, ExecutionException, TimeoutException { - triggerUIAndWait(getReadyToPay()); + mPaymentRequestTestRule.triggerUIAndWait(mPaymentRequestTestRule.getReadyToPay()); // Edit the only complete card. - clickInPaymentMethodAndWait(R.id.payments_section, getReadyForInput()); - clickInPaymentMethodAndWait(R.id.payments_open_editor_pencil_button, getReadyToEdit()); + mPaymentRequestTestRule.clickInPaymentMethodAndWait( + R.id.payments_section, mPaymentRequestTestRule.getReadyForInput()); + mPaymentRequestTestRule.clickInPaymentMethodAndWait( + R.id.payments_open_editor_pencil_button, mPaymentRequestTestRule.getReadyToEdit()); // Jon Doe is selected as the billing address. - assertTrue(getSpinnerSelectionTextInCardEditor(BILLING_ADDRESS_DROPDOWN_INDEX) - .equals("Jon Doe, 340 Main St, Los Angeles, CA 90291")); + Assert.assertTrue( + mPaymentRequestTestRule + .getSpinnerSelectionTextInCardEditor(BILLING_ADDRESS_DROPDOWN_INDEX) + .equals("Jon Doe, 340 Main St, Los Angeles, CA 90291")); // The incomplete addresses in the dropdown contain edit required messages. - assertTrue(getSpinnerTextAtPositionInCardEditor(BILLING_ADDRESS_DROPDOWN_INDEX, 4) - .endsWith("Name required")); - assertTrue(getSpinnerTextAtPositionInCardEditor(BILLING_ADDRESS_DROPDOWN_INDEX, - 5).endsWith("More information required")); - assertTrue(getSpinnerTextAtPositionInCardEditor(BILLING_ADDRESS_DROPDOWN_INDEX, 6) - .endsWith("Enter a valid address")); + Assert.assertTrue( + mPaymentRequestTestRule + .getSpinnerTextAtPositionInCardEditor(BILLING_ADDRESS_DROPDOWN_INDEX, 4) + .endsWith("Name required")); + Assert.assertTrue( + mPaymentRequestTestRule + .getSpinnerTextAtPositionInCardEditor(BILLING_ADDRESS_DROPDOWN_INDEX, 5) + .endsWith("More information required")); + Assert.assertTrue( + mPaymentRequestTestRule + .getSpinnerTextAtPositionInCardEditor(BILLING_ADDRESS_DROPDOWN_INDEX, 6) + .endsWith("Enter a valid address")); // Selects the fifth billing addresss that misses recipient name brings up the address // editor. - setSpinnerSelectionsInCardEditorAndWait( - new int[] {DECEMBER, NEXT_YEAR, 4}, getReadyToEdit()); - clickInEditorAndWait(R.id.payments_edit_cancel_button, getReadyToEdit()); + mPaymentRequestTestRule.setSpinnerSelectionsInCardEditorAndWait( + new int[] {DECEMBER, NEXT_YEAR, 4}, mPaymentRequestTestRule.getReadyToEdit()); + mPaymentRequestTestRule.clickInEditorAndWait( + R.id.payments_edit_cancel_button, mPaymentRequestTestRule.getReadyToEdit()); // The previous selected address should be selected after canceling out from edit. - assertTrue(getSpinnerSelectionTextInCardEditor(BILLING_ADDRESS_DROPDOWN_INDEX) - .equals("Jon Doe, 340 Main St, Los Angeles, CA 90291")); + Assert.assertTrue( + mPaymentRequestTestRule + .getSpinnerSelectionTextInCardEditor(BILLING_ADDRESS_DROPDOWN_INDEX) + .equals("Jon Doe, 340 Main St, Los Angeles, CA 90291")); } }
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestBillingAddressWithoutPhoneTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestBillingAddressWithoutPhoneTest.java index 72e0543..1352ed3c 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestBillingAddressWithoutPhoneTest.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestBillingAddressWithoutPhoneTest.java
@@ -4,14 +4,27 @@ package org.chromium.chrome.browser.payments; +import static org.chromium.chrome.browser.payments.PaymentRequestTestRule.DECEMBER; +import static org.chromium.chrome.browser.payments.PaymentRequestTestRule.NEXT_YEAR; + import android.content.DialogInterface; import android.support.test.filters.MediumTest; +import org.junit.Assert; +import org.junit.Rule; +import org.junit.Test; +import org.junit.runner.RunWith; + +import org.chromium.base.test.util.CommandLineFlags; import org.chromium.base.test.util.Feature; import org.chromium.chrome.R; +import org.chromium.chrome.browser.ChromeSwitches; import org.chromium.chrome.browser.autofill.AutofillTestHelper; import org.chromium.chrome.browser.autofill.PersonalDataManager.AutofillProfile; import org.chromium.chrome.browser.autofill.PersonalDataManager.CreditCard; +import org.chromium.chrome.browser.payments.PaymentRequestTestRule.MainActivityStartCallback; +import org.chromium.chrome.test.ChromeActivityTestRule; +import org.chromium.chrome.test.ChromeJUnit4ClassRunner; import java.util.concurrent.ExecutionException; import java.util.concurrent.TimeoutException; @@ -19,7 +32,17 @@ /** * A payment integration test for biling addresses without a phone. */ -public class PaymentRequestBillingAddressWithoutPhoneTest extends PaymentRequestTestBase { +@RunWith(ChromeJUnit4ClassRunner.class) +@CommandLineFlags.Add({ + ChromeSwitches.DISABLE_FIRST_RUN_EXPERIENCE, + ChromeActivityTestRule.DISABLE_NETWORK_PREDICTION_FLAG, +}) +public class PaymentRequestBillingAddressWithoutPhoneTest implements MainActivityStartCallback { + + @Rule + public PaymentRequestTestRule mPaymentRequestTestRule = + new PaymentRequestTestRule("payment_request_free_shipping_test.html", this); + /* * The index at which the option to add a billing address is located in the billing address * selection dropdown. @@ -29,10 +52,6 @@ /** The index of the billing address dropdown in the card editor. */ private static final int BILLING_ADDRESS_DROPDOWN_INDEX = 2; - public PaymentRequestBillingAddressWithoutPhoneTest() { - super("payment_request_free_shipping_test.html"); - } - @Override public void onMainActivityStarted() throws InterruptedException, ExecutionException, TimeoutException { @@ -52,71 +71,93 @@ helper.setProfileUseStatsForTesting(address_with_phone, 5, 5); } + @Test @MediumTest @Feature({"Payments"}) public void testCanPayWithBillingNoPhone() throws InterruptedException, ExecutionException, TimeoutException { - triggerUIAndWait(getReadyToPay()); - clickAndWait(R.id.button_primary, getReadyForUnmaskInput()); - setTextInCardUnmaskDialogAndWait(R.id.card_unmask_input, "123", getReadyToUnmask()); - clickCardUnmaskButtonAndWait(DialogInterface.BUTTON_POSITIVE, getDismissed()); - expectResultContains(new String[] {"Jon NoPhone"}); + mPaymentRequestTestRule.triggerUIAndWait(mPaymentRequestTestRule.getReadyToPay()); + mPaymentRequestTestRule.clickAndWait( + R.id.button_primary, mPaymentRequestTestRule.getReadyForUnmaskInput()); + mPaymentRequestTestRule.setTextInCardUnmaskDialogAndWait( + R.id.card_unmask_input, "123", mPaymentRequestTestRule.getReadyToUnmask()); + mPaymentRequestTestRule.clickCardUnmaskButtonAndWait( + DialogInterface.BUTTON_POSITIVE, mPaymentRequestTestRule.getDismissed()); + mPaymentRequestTestRule.expectResultContains(new String[] {"Jon NoPhone"}); } + @Test @MediumTest @Feature({"Payments"}) public void testCanSelectBillingAddressWithoutPhone() throws InterruptedException, ExecutionException, TimeoutException { - triggerUIAndWait(getReadyToPay()); + mPaymentRequestTestRule.triggerUIAndWait(mPaymentRequestTestRule.getReadyToPay()); // Go edit the credit card. - clickInPaymentMethodAndWait(R.id.payments_section, getReadyForInput()); - clickOnPaymentMethodSuggestionEditIconAndWait(0, getReadyToEdit()); + mPaymentRequestTestRule.clickInPaymentMethodAndWait( + R.id.payments_section, mPaymentRequestTestRule.getReadyForInput()); + mPaymentRequestTestRule.clickOnPaymentMethodSuggestionEditIconAndWait( + 0, mPaymentRequestTestRule.getReadyToEdit()); // Make sure that the currently selected address is valid and can be selected (does not // include error messages). - assertTrue(getSpinnerSelectionTextInCardEditor(BILLING_ADDRESS_DROPDOWN_INDEX) - .equals("Jon NoPhone, 340 Main St, Los Angeles, CA 90291")); + Assert.assertTrue( + mPaymentRequestTestRule + .getSpinnerSelectionTextInCardEditor(BILLING_ADDRESS_DROPDOWN_INDEX) + .equals("Jon NoPhone, 340 Main St, Los Angeles, CA 90291")); // Even though the current billing address is valid, the one with a phone number should be // suggested first if the user wants to change it. - assertTrue(getSpinnerTextAtPositionInCardEditor(BILLING_ADDRESS_DROPDOWN_INDEX, - 0).equals("Rob Phone, 340 Main St, Los Angeles, CA 90291")); + Assert.assertTrue( + mPaymentRequestTestRule + .getSpinnerTextAtPositionInCardEditor(BILLING_ADDRESS_DROPDOWN_INDEX, 0) + .equals("Rob Phone, 340 Main St, Los Angeles, CA 90291")); } + @Test @MediumTest @Feature({"Payments"}) public void testCantSelectShippingAddressWithoutPhone() throws InterruptedException, ExecutionException, TimeoutException { - triggerUIAndWait(getReadyToPay()); - clickInShippingSummaryAndWait(R.id.payments_section, getReadyForInput()); + mPaymentRequestTestRule.triggerUIAndWait(mPaymentRequestTestRule.getReadyToPay()); + mPaymentRequestTestRule.clickInShippingSummaryAndWait( + R.id.payments_section, mPaymentRequestTestRule.getReadyForInput()); // The first suggestion should be the address with a phone. - assertTrue(getShippingAddressSuggestionLabel(0).contains("Rob Phone")); - assertFalse(getShippingAddressSuggestionLabel(0).endsWith("Phone number required")); + Assert.assertTrue( + mPaymentRequestTestRule.getShippingAddressSuggestionLabel(0).contains("Rob Phone")); + Assert.assertFalse(mPaymentRequestTestRule.getShippingAddressSuggestionLabel(0).endsWith( + "Phone number required")); // The address without a phone should be suggested after with a message indicating that the // phone number is required. - assertTrue(getShippingAddressSuggestionLabel(1).contains("Jon NoPhone")); - assertTrue(getShippingAddressSuggestionLabel(1).endsWith("Phone number required")); + Assert.assertTrue(mPaymentRequestTestRule.getShippingAddressSuggestionLabel(1).contains( + "Jon NoPhone")); + Assert.assertTrue(mPaymentRequestTestRule.getShippingAddressSuggestionLabel(1).endsWith( + "Phone number required")); } + @Test @MediumTest @Feature({"Payments"}) public void testCantAddNewBillingAddressWithoutPhone() throws InterruptedException, ExecutionException, TimeoutException { - triggerUIAndWait(getReadyToPay()); - clickInPaymentMethodAndWait(R.id.payments_section, getReadyForInput()); - clickInPaymentMethodAndWait(R.id.payments_add_option_button, getReadyToEdit()); + mPaymentRequestTestRule.triggerUIAndWait(mPaymentRequestTestRule.getReadyToPay()); + mPaymentRequestTestRule.clickInPaymentMethodAndWait( + R.id.payments_section, mPaymentRequestTestRule.getReadyForInput()); + mPaymentRequestTestRule.clickInPaymentMethodAndWait( + R.id.payments_add_option_button, mPaymentRequestTestRule.getReadyToEdit()); // Add a new billing address without a phone. - setSpinnerSelectionsInCardEditorAndWait( - new int[] {DECEMBER, NEXT_YEAR, ADD_BILLING_ADDRESS}, getReadyToEdit()); - setTextInEditorAndWait( + mPaymentRequestTestRule.setSpinnerSelectionsInCardEditorAndWait( + new int[] {DECEMBER, NEXT_YEAR, ADD_BILLING_ADDRESS}, + mPaymentRequestTestRule.getReadyToEdit()); + mPaymentRequestTestRule.setTextInEditorAndWait( new String[] {"Seb Doe", "Google", "340 Main St", "Los Angeles", "CA", "90291", ""}, - getEditorTextUpdate()); + mPaymentRequestTestRule.getEditorTextUpdate()); // Trying to add the address without a phone number should fail. - clickInEditorAndWait(R.id.payments_edit_done_button, getEditorValidationError()); + mPaymentRequestTestRule.clickInEditorAndWait( + R.id.payments_edit_done_button, mPaymentRequestTestRule.getEditorValidationError()); } }
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestBlobUrlTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestBlobUrlTest.java index 844d51f..3d4c030 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestBlobUrlTest.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestBlobUrlTest.java
@@ -6,27 +6,38 @@ import android.support.test.filters.MediumTest; +import org.junit.Rule; +import org.junit.Test; +import org.junit.runner.RunWith; + +import org.chromium.base.test.util.CommandLineFlags; import org.chromium.base.test.util.Feature; +import org.chromium.chrome.browser.ChromeSwitches; +import org.chromium.chrome.test.ChromeActivityTestRule; +import org.chromium.chrome.test.ChromeJUnit4ClassRunner; import java.util.concurrent.ExecutionException; import java.util.concurrent.TimeoutException; /** Web payments test for blob URL. */ -public class PaymentRequestBlobUrlTest extends PaymentRequestTestBase { - public PaymentRequestBlobUrlTest() { - super("payment_request_blob_url_test.html"); - } +@RunWith(ChromeJUnit4ClassRunner.class) +@CommandLineFlags.Add({ + ChromeSwitches.DISABLE_FIRST_RUN_EXPERIENCE, + ChromeActivityTestRule.DISABLE_NETWORK_PREDICTION_FLAG, +}) +public class PaymentRequestBlobUrlTest { + @Rule + public PaymentRequestTestRule mPaymentRequestTestRule = + new PaymentRequestTestRule("payment_request_blob_url_test.html"); - @Override - public void onMainActivityStarted() - throws InterruptedException, ExecutionException, TimeoutException {} - + @Test @MediumTest @Feature({"Payments"}) public void test() throws InterruptedException, ExecutionException, TimeoutException { - openPageAndClickNode("buy"); - assertWaitForPageScaleFactorMatch(2); - expectResultContains(new String[] {"SecurityError: Failed to construct 'PaymentRequest': " - + "Must be in a secure context"}); + mPaymentRequestTestRule.openPageAndClickNode("buy"); + mPaymentRequestTestRule.assertWaitForPageScaleFactorMatch(2); + mPaymentRequestTestRule.expectResultContains( + new String[] {"SecurityError: Failed to construct 'PaymentRequest': " + + "Must be in a secure context"}); } }
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestCanMakePaymentMetricsTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestCanMakePaymentMetricsTest.java index 053815c..08487930 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestCanMakePaymentMetricsTest.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestCanMakePaymentMetricsTest.java
@@ -4,15 +4,28 @@ package org.chromium.chrome.browser.payments; +import static org.chromium.chrome.browser.payments.PaymentRequestTestRule.HAVE_INSTRUMENTS; +import static org.chromium.chrome.browser.payments.PaymentRequestTestRule.IMMEDIATE_RESPONSE; + import android.content.DialogInterface; import android.support.test.filters.MediumTest; +import org.junit.Assert; +import org.junit.Rule; +import org.junit.Test; +import org.junit.runner.RunWith; + import org.chromium.base.ThreadUtils; import org.chromium.base.metrics.RecordHistogram; +import org.chromium.base.test.util.CommandLineFlags; import org.chromium.base.test.util.Feature; import org.chromium.chrome.R; +import org.chromium.chrome.browser.ChromeSwitches; import org.chromium.chrome.browser.autofill.AutofillTestHelper; import org.chromium.chrome.browser.autofill.PersonalDataManager.AutofillProfile; +import org.chromium.chrome.browser.payments.PaymentRequestTestRule.MainActivityStartCallback; +import org.chromium.chrome.test.ChromeActivityTestRule; +import org.chromium.chrome.test.ChromeJUnit4ClassRunner; import java.util.concurrent.ExecutionException; import java.util.concurrent.TimeoutException; @@ -20,10 +33,15 @@ /** * A payment integration test for the correct log of the CanMakePayment metrics. */ -public class PaymentRequestCanMakePaymentMetricsTest extends PaymentRequestTestBase { - public PaymentRequestCanMakePaymentMetricsTest() { - super("payment_request_can_make_payment_metrics_test.html"); - } +@RunWith(ChromeJUnit4ClassRunner.class) +@CommandLineFlags.Add({ + ChromeSwitches.DISABLE_FIRST_RUN_EXPERIENCE, + ChromeActivityTestRule.DISABLE_NETWORK_PREDICTION_FLAG, +}) +public class PaymentRequestCanMakePaymentMetricsTest implements MainActivityStartCallback { + @Rule + public PaymentRequestTestRule mPaymentRequestTestRule = + new PaymentRequestTestRule("payment_request_can_make_payment_metrics_test.html", this); @Override public void onMainActivityStarted() @@ -39,39 +57,41 @@ * calling it, receiving no as a response, still showing the Payment Request and the user aborts * the flow. */ + @Test @MediumTest @Feature({"Payments"}) public void testCannotMakePayment_Abort() throws InterruptedException, ExecutionException, TimeoutException { // Initiate a payment request. - triggerUIAndWait("queryShow", getReadyForInput()); + mPaymentRequestTestRule.triggerUIAndWait( + "queryShow", mPaymentRequestTestRule.getReadyForInput()); // Press the back button. - int callCount = getDismissed().getCallCount(); + int callCount = mPaymentRequestTestRule.getDismissed().getCallCount(); ThreadUtils.runOnUiThreadBlocking(new Runnable() { @Override public void run() { - getPaymentRequestUI().getDialogForTest().onBackPressed(); + mPaymentRequestTestRule.getPaymentRequestUI().getDialogForTest().onBackPressed(); } }); - getDismissed().waitForCallback(callCount); - expectResultContains(new String[] {"Request cancelled"}); + mPaymentRequestTestRule.getDismissed().waitForCallback(callCount); + mPaymentRequestTestRule.expectResultContains(new String[] {"Request cancelled"}); // CanMakePayment was queried. - assertEquals(1, + Assert.assertEquals(1, RecordHistogram.getHistogramValueCountForTesting( "PaymentRequest.CanMakePayment.Usage", JourneyLogger.CAN_MAKE_PAYMENT_USED)); // The CanMakePayment effect on show should be recorded as being false and shown. - assertEquals(1, + Assert.assertEquals(1, RecordHistogram.getHistogramValueCountForTesting( "PaymentRequest.CanMakePayment.Used.EffectOnShow", JourneyLogger.CMP_SHOW_DID_SHOW)); // There should be a record for an abort when CanMakePayment is false but the PR is shown to // the user. - assertEquals(1, + Assert.assertEquals(1, RecordHistogram.getHistogramValueCountForTesting( "PaymentRequest.CanMakePayment.Used.FalseWithShowEffectOnCompletion", JourneyLogger.COMPLETION_STATUS_USER_ABORTED)); @@ -82,40 +102,48 @@ * calling it, receiving no as a response, still showing the Payment Request and the user * completes the flow. */ + @Test @MediumTest @Feature({"Payments"}) public void testCannotMakePayment_Complete() throws InterruptedException, ExecutionException, TimeoutException { - triggerUIAndWait("queryShow", getReadyForInput()); + mPaymentRequestTestRule.triggerUIAndWait( + "queryShow", mPaymentRequestTestRule.getReadyForInput()); // Add a new credit card. - clickInPaymentMethodAndWait(R.id.payments_section, getReadyToEdit()); - setSpinnerSelectionsInCardEditorAndWait( - new int[] {11, 1, 0}, getBillingAddressChangeProcessed()); - setTextInCardEditorAndWait( - new String[] {"4111111111111111", "Jon Doe"}, getEditorTextUpdate()); - clickInCardEditorAndWait(R.id.payments_edit_done_button, getReadyToPay()); + mPaymentRequestTestRule.clickInPaymentMethodAndWait( + R.id.payments_section, mPaymentRequestTestRule.getReadyToEdit()); + mPaymentRequestTestRule.setSpinnerSelectionsInCardEditorAndWait( + new int[] {11, 1, 0}, mPaymentRequestTestRule.getBillingAddressChangeProcessed()); + mPaymentRequestTestRule.setTextInCardEditorAndWait( + new String[] {"4111111111111111", "Jon Doe"}, + mPaymentRequestTestRule.getEditorTextUpdate()); + mPaymentRequestTestRule.clickInCardEditorAndWait( + R.id.payments_edit_done_button, mPaymentRequestTestRule.getReadyToPay()); // Complete the transaction. - clickAndWait(R.id.button_primary, getReadyForUnmaskInput()); - setTextInCardUnmaskDialogAndWait(R.id.card_unmask_input, "123", getReadyToUnmask()); - clickCardUnmaskButtonAndWait(DialogInterface.BUTTON_POSITIVE, getDismissed()); + mPaymentRequestTestRule.clickAndWait( + R.id.button_primary, mPaymentRequestTestRule.getReadyForUnmaskInput()); + mPaymentRequestTestRule.setTextInCardUnmaskDialogAndWait( + R.id.card_unmask_input, "123", mPaymentRequestTestRule.getReadyToUnmask()); + mPaymentRequestTestRule.clickCardUnmaskButtonAndWait( + DialogInterface.BUTTON_POSITIVE, mPaymentRequestTestRule.getDismissed()); // CanMakePayment was queried. - assertEquals(1, + Assert.assertEquals(1, RecordHistogram.getHistogramValueCountForTesting( "PaymentRequest.CanMakePayment.Usage", JourneyLogger.CAN_MAKE_PAYMENT_USED)); // The CanMakePayment effect on show should be recorded as being false and shown. - assertEquals(1, + Assert.assertEquals(1, RecordHistogram.getHistogramValueCountForTesting( "PaymentRequest.CanMakePayment.Used.EffectOnShow", JourneyLogger.CMP_SHOW_DID_SHOW)); // There should be a record for a completion when CanMakePayment is false but the PR is // shown to the user. - assertEquals(1, + Assert.assertEquals(1, RecordHistogram.getHistogramValueCountForTesting( "PaymentRequest.CanMakePayment.Used.FalseWithShowEffectOnCompletion", JourneyLogger.COMPLETION_STATUS_COMPLETED)); @@ -126,35 +154,37 @@ * calling it, receiving yeas as a response, showing the Payment Request and the user aborts the * flow. */ + @Test @MediumTest @Feature({"Payments"}) public void testCanMakePayment_Abort() throws InterruptedException, ExecutionException, TimeoutException { // Install the app so CanMakePayment returns true. - installPaymentApp(HAVE_INSTRUMENTS, IMMEDIATE_RESPONSE); + mPaymentRequestTestRule.installPaymentApp(HAVE_INSTRUMENTS, IMMEDIATE_RESPONSE); // Initiate a payment request. - triggerUIAndWait("queryShow", getReadyForInput()); + mPaymentRequestTestRule.triggerUIAndWait( + "queryShow", mPaymentRequestTestRule.getReadyForInput()); // Press the back button. - int callCount = getDismissed().getCallCount(); + int callCount = mPaymentRequestTestRule.getDismissed().getCallCount(); ThreadUtils.runOnUiThreadBlocking(new Runnable() { @Override public void run() { - getPaymentRequestUI().getDialogForTest().onBackPressed(); + mPaymentRequestTestRule.getPaymentRequestUI().getDialogForTest().onBackPressed(); } }); - getDismissed().waitForCallback(callCount); - expectResultContains(new String[] {"Request cancelled"}); + mPaymentRequestTestRule.getDismissed().waitForCallback(callCount); + mPaymentRequestTestRule.expectResultContains(new String[] {"Request cancelled"}); // CanMakePayment was queried. - assertEquals(1, + Assert.assertEquals(1, RecordHistogram.getHistogramValueCountForTesting( "PaymentRequest.CanMakePayment.Usage", JourneyLogger.CAN_MAKE_PAYMENT_USED)); // The CanMakePayment effect on show should be recorded as being false and shown. - assertEquals(1, + Assert.assertEquals(1, RecordHistogram.getHistogramValueCountForTesting( "PaymentRequest.CanMakePayment.Used.EffectOnShow", JourneyLogger.CMP_SHOW_DID_SHOW @@ -162,7 +192,7 @@ // There should be a record for an abort when CanMakePayment is false but the PR is shown to // the user. - assertEquals(1, + Assert.assertEquals(1, RecordHistogram.getHistogramValueCountForTesting( "PaymentRequest.CanMakePayment.Used.TrueWithShowEffectOnCompletion", JourneyLogger.COMPLETION_STATUS_USER_ABORTED)); @@ -173,25 +203,28 @@ * calling it, receiving yeas as a response, showing the Payment Request and the user completes * the flow. */ + @Test @MediumTest @Feature({"Payments"}) public void testCanMakePayment_Complete() throws InterruptedException, ExecutionException, TimeoutException { // Install the app so CanMakePayment returns true. - installPaymentApp(HAVE_INSTRUMENTS, IMMEDIATE_RESPONSE); + mPaymentRequestTestRule.installPaymentApp(HAVE_INSTRUMENTS, IMMEDIATE_RESPONSE); // Initiate an complete a payment request. - triggerUIAndWait("queryShow", getReadyForInput()); - clickAndWait(R.id.button_primary, getDismissed()); + mPaymentRequestTestRule.triggerUIAndWait( + "queryShow", mPaymentRequestTestRule.getReadyForInput()); + mPaymentRequestTestRule.clickAndWait( + R.id.button_primary, mPaymentRequestTestRule.getDismissed()); // CanMakePayment was queried. - assertEquals(1, + Assert.assertEquals(1, RecordHistogram.getHistogramValueCountForTesting( "PaymentRequest.CanMakePayment.Usage", JourneyLogger.CAN_MAKE_PAYMENT_USED)); // The CanMakePayment effect on show should be recorded as being false and shown. - assertEquals(1, + Assert.assertEquals(1, RecordHistogram.getHistogramValueCountForTesting( "PaymentRequest.CanMakePayment.Used.EffectOnShow", JourneyLogger.CMP_SHOW_DID_SHOW @@ -199,7 +232,7 @@ // There should be a record for an abort when CanMakePayment is false but the PR is shown to // the user. - assertEquals(1, + Assert.assertEquals(1, RecordHistogram.getHistogramValueCountForTesting( "PaymentRequest.CanMakePayment.Used.TrueWithShowEffectOnCompletion", JourneyLogger.COMPLETION_STATUS_COMPLETED)); @@ -209,33 +242,35 @@ * Tests that the CanMakePayment metrics are correctly logged for the case of a merchant * not calling it but still showing the Payment Request and the user aborts the flow. */ + @Test @MediumTest @Feature({"Payments"}) public void testNoQuery_Abort() throws InterruptedException, ExecutionException, TimeoutException { // Initiate a payment request. - triggerUIAndWait("noQueryShow", getReadyForInput()); + mPaymentRequestTestRule.triggerUIAndWait( + "noQueryShow", mPaymentRequestTestRule.getReadyForInput()); // Press the back button. - int callCount = getDismissed().getCallCount(); + int callCount = mPaymentRequestTestRule.getDismissed().getCallCount(); ThreadUtils.runOnUiThreadBlocking(new Runnable() { @Override public void run() { - getPaymentRequestUI().getDialogForTest().onBackPressed(); + mPaymentRequestTestRule.getPaymentRequestUI().getDialogForTest().onBackPressed(); } }); - getDismissed().waitForCallback(callCount); - expectResultContains(new String[] {"Request cancelled"}); + mPaymentRequestTestRule.getDismissed().waitForCallback(callCount); + mPaymentRequestTestRule.expectResultContains(new String[] {"Request cancelled"}); // CanMakePayment was not queried. - assertEquals(1, + Assert.assertEquals(1, RecordHistogram.getHistogramValueCountForTesting( "PaymentRequest.CanMakePayment.Usage", JourneyLogger.CAN_MAKE_PAYMENT_NOT_USED)); // There should be a record for an abort when CanMakePayment is not called but the PR is // shown to the user. - assertEquals(1, + Assert.assertEquals(1, RecordHistogram.getHistogramValueCountForTesting( "PaymentRequest.CanMakePayment.NotUsed.WithShowEffectOnCompletion", JourneyLogger.COMPLETION_STATUS_USER_ABORTED)); @@ -245,26 +280,29 @@ * Tests that the CanMakePayment metrics are correctly logged for the case of a merchant * not calling it but still showing the Payment Request and the user completes the flow. */ + @Test @MediumTest @Feature({"Payments"}) public void testNoQuery_Completes() throws InterruptedException, ExecutionException, TimeoutException { // Install the app so the user can complete the Payment Request. - installPaymentApp(HAVE_INSTRUMENTS, IMMEDIATE_RESPONSE); + mPaymentRequestTestRule.installPaymentApp(HAVE_INSTRUMENTS, IMMEDIATE_RESPONSE); // Initiate a payment request. - triggerUIAndWait("noQueryShow", getReadyForInput()); - clickAndWait(R.id.button_primary, getDismissed()); + mPaymentRequestTestRule.triggerUIAndWait( + "noQueryShow", mPaymentRequestTestRule.getReadyForInput()); + mPaymentRequestTestRule.clickAndWait( + R.id.button_primary, mPaymentRequestTestRule.getDismissed()); // CanMakePayment was not queried. - assertEquals(1, + Assert.assertEquals(1, RecordHistogram.getHistogramValueCountForTesting( "PaymentRequest.CanMakePayment.Usage", JourneyLogger.CAN_MAKE_PAYMENT_NOT_USED)); // There should be a record for a completion when CanMakePayment is not called but the PR is // shown to the user. - assertEquals(1, + Assert.assertEquals(1, RecordHistogram.getHistogramValueCountForTesting( "PaymentRequest.CanMakePayment.NotUsed.WithShowEffectOnCompletion", JourneyLogger.COMPLETION_STATUS_COMPLETED));
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestCanMakePaymentQueryNoCardTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestCanMakePaymentQueryNoCardTest.java index 13b70ce..3b3b6c7 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestCanMakePaymentQueryNoCardTest.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestCanMakePaymentQueryNoCardTest.java
@@ -4,12 +4,26 @@ package org.chromium.chrome.browser.payments; +import static org.chromium.chrome.browser.payments.PaymentRequestTestRule.DELAYED_RESPONSE; +import static org.chromium.chrome.browser.payments.PaymentRequestTestRule.HAVE_INSTRUMENTS; +import static org.chromium.chrome.browser.payments.PaymentRequestTestRule.IMMEDIATE_RESPONSE; +import static org.chromium.chrome.browser.payments.PaymentRequestTestRule.NO_INSTRUMENTS; + import android.support.test.filters.MediumTest; +import org.junit.Rule; +import org.junit.Test; +import org.junit.runner.RunWith; + +import org.chromium.base.test.util.CommandLineFlags; import org.chromium.base.test.util.Feature; import org.chromium.chrome.R; +import org.chromium.chrome.browser.ChromeSwitches; import org.chromium.chrome.browser.autofill.AutofillTestHelper; import org.chromium.chrome.browser.autofill.PersonalDataManager.CreditCard; +import org.chromium.chrome.browser.payments.PaymentRequestTestRule.MainActivityStartCallback; +import org.chromium.chrome.test.ChromeActivityTestRule; +import org.chromium.chrome.test.ChromeJUnit4ClassRunner; import java.util.concurrent.ExecutionException; import java.util.concurrent.TimeoutException; @@ -18,10 +32,15 @@ * A payment integration test for checking whether user can make a payment via either payment * app or a credit card. This user does not have a complete credit card on file. */ -public class PaymentRequestCanMakePaymentQueryNoCardTest extends PaymentRequestTestBase { - public PaymentRequestCanMakePaymentQueryNoCardTest() { - super("payment_request_can_make_payment_query_test.html"); - } +@RunWith(ChromeJUnit4ClassRunner.class) +@CommandLineFlags.Add({ + ChromeSwitches.DISABLE_FIRST_RUN_EXPERIENCE, + ChromeActivityTestRule.DISABLE_NETWORK_PREDICTION_FLAG, +}) +public class PaymentRequestCanMakePaymentQueryNoCardTest implements MainActivityStartCallback { + @Rule + public PaymentRequestTestRule mPaymentRequestTestRule = + new PaymentRequestTestRule("payment_request_can_make_payment_query_test.html", this); @Override public void onMainActivityStarted() throws InterruptedException, ExecutionException, @@ -33,47 +52,57 @@ R.drawable.pr_visa, "" /* billingAddressId */, "" /* serverId */)); } + @Test @MediumTest @Feature({"Payments"}) - public void testNoBobPayInstalled() throws InterruptedException, ExecutionException, - TimeoutException { - openPageAndClickBuyAndWait(getCanMakePaymentQueryResponded()); - expectResultContains(new String[]{"false"}); + public void testNoBobPayInstalled() + throws InterruptedException, ExecutionException, TimeoutException { + mPaymentRequestTestRule.openPageAndClickBuyAndWait( + mPaymentRequestTestRule.getCanMakePaymentQueryResponded()); + mPaymentRequestTestRule.expectResultContains(new String[] {"false"}); } + @Test @MediumTest @Feature({"Payments"}) - public void testNoInstrumentsInFastBobPay() throws InterruptedException, ExecutionException, - TimeoutException { - installPaymentApp(NO_INSTRUMENTS, IMMEDIATE_RESPONSE); - openPageAndClickBuyAndWait(getCanMakePaymentQueryResponded()); - expectResultContains(new String[]{"false"}); + public void testNoInstrumentsInFastBobPay() + throws InterruptedException, ExecutionException, TimeoutException { + mPaymentRequestTestRule.installPaymentApp(NO_INSTRUMENTS, IMMEDIATE_RESPONSE); + mPaymentRequestTestRule.openPageAndClickBuyAndWait( + mPaymentRequestTestRule.getCanMakePaymentQueryResponded()); + mPaymentRequestTestRule.expectResultContains(new String[] {"false"}); } + @Test @MediumTest @Feature({"Payments"}) - public void testNoInstrumentsInSlowBobPay() throws InterruptedException, ExecutionException, - TimeoutException { - installPaymentApp(NO_INSTRUMENTS, DELAYED_RESPONSE); - openPageAndClickBuyAndWait(getCanMakePaymentQueryResponded()); - expectResultContains(new String[]{"false"}); + public void testNoInstrumentsInSlowBobPay() + throws InterruptedException, ExecutionException, TimeoutException { + mPaymentRequestTestRule.installPaymentApp(NO_INSTRUMENTS, DELAYED_RESPONSE); + mPaymentRequestTestRule.openPageAndClickBuyAndWait( + mPaymentRequestTestRule.getCanMakePaymentQueryResponded()); + mPaymentRequestTestRule.expectResultContains(new String[] {"false"}); } + @Test @MediumTest @Feature({"Payments"}) - public void testPayViaFastBobPay() throws InterruptedException, ExecutionException, - TimeoutException { - installPaymentApp(HAVE_INSTRUMENTS, IMMEDIATE_RESPONSE); - openPageAndClickBuyAndWait(getCanMakePaymentQueryResponded()); - expectResultContains(new String[]{"true"}); + public void testPayViaFastBobPay() + throws InterruptedException, ExecutionException, TimeoutException { + mPaymentRequestTestRule.installPaymentApp(HAVE_INSTRUMENTS, IMMEDIATE_RESPONSE); + mPaymentRequestTestRule.openPageAndClickBuyAndWait( + mPaymentRequestTestRule.getCanMakePaymentQueryResponded()); + mPaymentRequestTestRule.expectResultContains(new String[] {"true"}); } + @Test @MediumTest @Feature({"Payments"}) - public void testPayViaSlowBobPay() throws InterruptedException, ExecutionException, - TimeoutException { - installPaymentApp(HAVE_INSTRUMENTS, DELAYED_RESPONSE); - openPageAndClickBuyAndWait(getCanMakePaymentQueryResponded()); - expectResultContains(new String[]{"true"}); + public void testPayViaSlowBobPay() + throws InterruptedException, ExecutionException, TimeoutException { + mPaymentRequestTestRule.installPaymentApp(HAVE_INSTRUMENTS, DELAYED_RESPONSE); + mPaymentRequestTestRule.openPageAndClickBuyAndWait( + mPaymentRequestTestRule.getCanMakePaymentQueryResponded()); + mPaymentRequestTestRule.expectResultContains(new String[] {"true"}); } }
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestCanMakePaymentQueryTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestCanMakePaymentQueryTest.java index 20dc0a4..c5e22816 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestCanMakePaymentQueryTest.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestCanMakePaymentQueryTest.java
@@ -4,12 +4,26 @@ package org.chromium.chrome.browser.payments; +import static org.chromium.chrome.browser.payments.PaymentRequestTestRule.DELAYED_RESPONSE; +import static org.chromium.chrome.browser.payments.PaymentRequestTestRule.HAVE_INSTRUMENTS; +import static org.chromium.chrome.browser.payments.PaymentRequestTestRule.IMMEDIATE_RESPONSE; +import static org.chromium.chrome.browser.payments.PaymentRequestTestRule.NO_INSTRUMENTS; + import android.support.test.filters.MediumTest; +import org.junit.Rule; +import org.junit.Test; +import org.junit.runner.RunWith; + +import org.chromium.base.test.util.CommandLineFlags; import org.chromium.base.test.util.Feature; import org.chromium.chrome.R; +import org.chromium.chrome.browser.ChromeSwitches; import org.chromium.chrome.browser.autofill.AutofillTestHelper; import org.chromium.chrome.browser.autofill.PersonalDataManager.CreditCard; +import org.chromium.chrome.browser.payments.PaymentRequestTestRule.MainActivityStartCallback; +import org.chromium.chrome.test.ChromeActivityTestRule; +import org.chromium.chrome.test.ChromeJUnit4ClassRunner; import java.util.concurrent.ExecutionException; import java.util.concurrent.TimeoutException; @@ -18,10 +32,15 @@ * A payment integration test for checking whether user can make a payment via either payment app or * a credit card. This user has a valid credit card without a billing address on file. */ -public class PaymentRequestCanMakePaymentQueryTest extends PaymentRequestTestBase { - public PaymentRequestCanMakePaymentQueryTest() { - super("payment_request_can_make_payment_query_test.html"); - } +@RunWith(ChromeJUnit4ClassRunner.class) +@CommandLineFlags.Add({ + ChromeSwitches.DISABLE_FIRST_RUN_EXPERIENCE, + ChromeActivityTestRule.DISABLE_NETWORK_PREDICTION_FLAG, +}) +public class PaymentRequestCanMakePaymentQueryTest implements MainActivityStartCallback { + @Rule + public PaymentRequestTestRule mPaymentRequestTestRule = + new PaymentRequestTestRule("payment_request_can_make_payment_query_test.html", this); @Override public void onMainActivityStarted() throws InterruptedException, ExecutionException, @@ -33,47 +52,57 @@ "" /* billingAddressId */, "" /* serverId */)); } + @Test @MediumTest @Feature({"Payments"}) - public void testNoBobPayInstalled() throws InterruptedException, ExecutionException, - TimeoutException { - openPageAndClickBuyAndWait(getCanMakePaymentQueryResponded()); - expectResultContains(new String[]{"true"}); + public void testNoBobPayInstalled() + throws InterruptedException, ExecutionException, TimeoutException { + mPaymentRequestTestRule.openPageAndClickBuyAndWait( + mPaymentRequestTestRule.getCanMakePaymentQueryResponded()); + mPaymentRequestTestRule.expectResultContains(new String[] {"true"}); } + @Test @MediumTest @Feature({"Payments"}) - public void testNoInstrumentsInFastBobPay() throws InterruptedException, ExecutionException, - TimeoutException { - installPaymentApp(NO_INSTRUMENTS, IMMEDIATE_RESPONSE); - openPageAndClickBuyAndWait(getCanMakePaymentQueryResponded()); - expectResultContains(new String[]{"true"}); + public void testNoInstrumentsInFastBobPay() + throws InterruptedException, ExecutionException, TimeoutException { + mPaymentRequestTestRule.installPaymentApp(NO_INSTRUMENTS, IMMEDIATE_RESPONSE); + mPaymentRequestTestRule.openPageAndClickBuyAndWait( + mPaymentRequestTestRule.getCanMakePaymentQueryResponded()); + mPaymentRequestTestRule.expectResultContains(new String[] {"true"}); } + @Test @MediumTest @Feature({"Payments"}) - public void testNoInstrumentsInSlowBobPay() throws InterruptedException, ExecutionException, - TimeoutException { - installPaymentApp(NO_INSTRUMENTS, DELAYED_RESPONSE); - openPageAndClickBuyAndWait(getCanMakePaymentQueryResponded()); - expectResultContains(new String[]{"true"}); + public void testNoInstrumentsInSlowBobPay() + throws InterruptedException, ExecutionException, TimeoutException { + mPaymentRequestTestRule.installPaymentApp(NO_INSTRUMENTS, DELAYED_RESPONSE); + mPaymentRequestTestRule.openPageAndClickBuyAndWait( + mPaymentRequestTestRule.getCanMakePaymentQueryResponded()); + mPaymentRequestTestRule.expectResultContains(new String[] {"true"}); } + @Test @MediumTest @Feature({"Payments"}) - public void testPayViaFastBobPay() throws InterruptedException, ExecutionException, - TimeoutException { - installPaymentApp(HAVE_INSTRUMENTS, IMMEDIATE_RESPONSE); - openPageAndClickBuyAndWait(getCanMakePaymentQueryResponded()); - expectResultContains(new String[]{"true"}); + public void testPayViaFastBobPay() + throws InterruptedException, ExecutionException, TimeoutException { + mPaymentRequestTestRule.installPaymentApp(HAVE_INSTRUMENTS, IMMEDIATE_RESPONSE); + mPaymentRequestTestRule.openPageAndClickBuyAndWait( + mPaymentRequestTestRule.getCanMakePaymentQueryResponded()); + mPaymentRequestTestRule.expectResultContains(new String[] {"true"}); } + @Test @MediumTest @Feature({"Payments"}) - public void testPayViaSlowBobPay() throws InterruptedException, ExecutionException, - TimeoutException { - installPaymentApp(HAVE_INSTRUMENTS, DELAYED_RESPONSE); - openPageAndClickBuyAndWait(getCanMakePaymentQueryResponded()); - expectResultContains(new String[]{"true"}); + public void testPayViaSlowBobPay() + throws InterruptedException, ExecutionException, TimeoutException { + mPaymentRequestTestRule.installPaymentApp(HAVE_INSTRUMENTS, DELAYED_RESPONSE); + mPaymentRequestTestRule.openPageAndClickBuyAndWait( + mPaymentRequestTestRule.getCanMakePaymentQueryResponded()); + mPaymentRequestTestRule.expectResultContains(new String[] {"true"}); } }
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestCardEditorAutoAdvanceTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestCardEditorAutoAdvanceTest.java index 8a28d2a5..d8b71c3 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestCardEditorAutoAdvanceTest.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestCardEditorAutoAdvanceTest.java
@@ -7,12 +7,22 @@ import android.support.test.filters.MediumTest; import android.view.View; +import org.junit.Assert; +import org.junit.Rule; +import org.junit.Test; +import org.junit.runner.RunWith; + import org.chromium.base.ThreadUtils; +import org.chromium.base.test.util.CommandLineFlags; import org.chromium.base.test.util.Feature; import org.chromium.chrome.R; +import org.chromium.chrome.browser.ChromeSwitches; import org.chromium.chrome.browser.autofill.AutofillTestHelper; import org.chromium.chrome.browser.autofill.PersonalDataManager.AutofillProfile; import org.chromium.chrome.browser.autofill.PersonalDataManager.CreditCard; +import org.chromium.chrome.browser.payments.PaymentRequestTestRule.MainActivityStartCallback; +import org.chromium.chrome.test.ChromeActivityTestRule; +import org.chromium.chrome.test.ChromeJUnit4ClassRunner; import java.util.concurrent.ExecutionException; import java.util.concurrent.TimeoutException; @@ -23,10 +33,15 @@ * Below valid test card numbers are from https://stripe.com/docs/testing#cards and * https://developers.braintreepayments.com/guides/unionpay/testing/javascript/v3 */ -public class PaymentRequestCardEditorAutoAdvanceTest extends PaymentRequestTestBase { - public PaymentRequestCardEditorAutoAdvanceTest() { - super("payment_request_free_shipping_test.html"); - } +@RunWith(ChromeJUnit4ClassRunner.class) +@CommandLineFlags.Add({ + ChromeSwitches.DISABLE_FIRST_RUN_EXPERIENCE, + ChromeActivityTestRule.DISABLE_NETWORK_PREDICTION_FLAG, +}) +public class PaymentRequestCardEditorAutoAdvanceTest implements MainActivityStartCallback { + @Rule + public PaymentRequestTestRule mPaymentRequestTestRule = + new PaymentRequestTestRule("payment_request_free_shipping_test.html", this); @Override public void onMainActivityStarted() @@ -42,27 +57,33 @@ billingAddressId, "" /* serverId */)); } + @Test @MediumTest @Feature({"Payments"}) public void test14DigitsCreditCard() throws InterruptedException, ExecutionException, TimeoutException { - triggerUIAndWait(getReadyToPay()); + mPaymentRequestTestRule.triggerUIAndWait(mPaymentRequestTestRule.getReadyToPay()); - clickInPaymentMethodAndWait(R.id.payments_section, getReadyForInput()); - clickInPaymentMethodAndWait(R.id.payments_add_option_button, getReadyToEdit()); + mPaymentRequestTestRule.clickInPaymentMethodAndWait( + R.id.payments_section, mPaymentRequestTestRule.getReadyForInput()); + mPaymentRequestTestRule.clickInPaymentMethodAndWait( + R.id.payments_add_option_button, mPaymentRequestTestRule.getReadyToEdit()); // Diners credit card. - final View focusedChildView = getCardEditorFocusedView(); - setTextInCardEditorAndWait(new String[] {"3056 9309 0259 0"}, getEditorTextUpdate()); - assertTrue(getCardEditorFocusedView() == focusedChildView); + final View focusedChildView = mPaymentRequestTestRule.getCardEditorFocusedView(); + mPaymentRequestTestRule.setTextInCardEditorAndWait( + new String[] {"3056 9309 0259 0"}, mPaymentRequestTestRule.getEditorTextUpdate()); + Assert.assertTrue(mPaymentRequestTestRule.getCardEditorFocusedView() == focusedChildView); // '3056 9309 0259 00' is an invalid 14 digits card number. - setTextInCardEditorAndWait(new String[] {"3056 9309 0259 00"}, getEditorTextUpdate()); - assertTrue(getCardEditorFocusedView() == focusedChildView); + mPaymentRequestTestRule.setTextInCardEditorAndWait( + new String[] {"3056 9309 0259 00"}, mPaymentRequestTestRule.getEditorTextUpdate()); + Assert.assertTrue(mPaymentRequestTestRule.getCardEditorFocusedView() == focusedChildView); // '3056 9309 0259 04' is a valid 14 digits card number. - setTextInCardEditorAndWait(new String[] {"3056 9309 0259 04"}, getEditorTextUpdate()); - assertTrue(getCardEditorFocusedView() != focusedChildView); + mPaymentRequestTestRule.setTextInCardEditorAndWait( + new String[] {"3056 9309 0259 04"}, mPaymentRequestTestRule.getEditorTextUpdate()); + Assert.assertTrue(mPaymentRequestTestRule.getCardEditorFocusedView() != focusedChildView); // Request focus to card number field after auto advancing above. ThreadUtils.runOnUiThreadBlocking(new Runnable() { @@ -71,31 +92,38 @@ focusedChildView.requestFocus(); } }); - setTextInCardEditorAndWait(new String[] {"3056 9309 0259 041"}, getEditorTextUpdate()); - assertTrue(getCardEditorFocusedView() == focusedChildView); + mPaymentRequestTestRule.setTextInCardEditorAndWait( + new String[] {"3056 9309 0259 041"}, mPaymentRequestTestRule.getEditorTextUpdate()); + Assert.assertTrue(mPaymentRequestTestRule.getCardEditorFocusedView() == focusedChildView); } + @Test @MediumTest @Feature({"Payments"}) public void test15DigitsCreditCard() throws InterruptedException, ExecutionException, TimeoutException { - triggerUIAndWait(getReadyToPay()); + mPaymentRequestTestRule.triggerUIAndWait(mPaymentRequestTestRule.getReadyToPay()); - clickInPaymentMethodAndWait(R.id.payments_section, getReadyForInput()); - clickInPaymentMethodAndWait(R.id.payments_add_option_button, getReadyToEdit()); + mPaymentRequestTestRule.clickInPaymentMethodAndWait( + R.id.payments_section, mPaymentRequestTestRule.getReadyForInput()); + mPaymentRequestTestRule.clickInPaymentMethodAndWait( + R.id.payments_add_option_button, mPaymentRequestTestRule.getReadyToEdit()); // American Express credit card. - final View focusedChildView = getCardEditorFocusedView(); - setTextInCardEditorAndWait(new String[] {"3782 822463 1000"}, getEditorTextUpdate()); - assertTrue(getCardEditorFocusedView() == focusedChildView); + final View focusedChildView = mPaymentRequestTestRule.getCardEditorFocusedView(); + mPaymentRequestTestRule.setTextInCardEditorAndWait( + new String[] {"3782 822463 1000"}, mPaymentRequestTestRule.getEditorTextUpdate()); + Assert.assertTrue(mPaymentRequestTestRule.getCardEditorFocusedView() == focusedChildView); // '3782 822463 10000' is an invalid 15 digits card number. - setTextInCardEditorAndWait(new String[] {"3782 822463 10000"}, getEditorTextUpdate()); - assertTrue(getCardEditorFocusedView() == focusedChildView); + mPaymentRequestTestRule.setTextInCardEditorAndWait( + new String[] {"3782 822463 10000"}, mPaymentRequestTestRule.getEditorTextUpdate()); + Assert.assertTrue(mPaymentRequestTestRule.getCardEditorFocusedView() == focusedChildView); // '3782 822463 10005' is a valid 15 digits card number. - setTextInCardEditorAndWait(new String[] {"3782 822463 10005"}, getEditorTextUpdate()); - assertTrue(getCardEditorFocusedView() != focusedChildView); + mPaymentRequestTestRule.setTextInCardEditorAndWait( + new String[] {"3782 822463 10005"}, mPaymentRequestTestRule.getEditorTextUpdate()); + Assert.assertTrue(mPaymentRequestTestRule.getCardEditorFocusedView() != focusedChildView); // Request focus to card number field after auto advancing above. ThreadUtils.runOnUiThreadBlocking(new Runnable() { @@ -104,39 +132,48 @@ focusedChildView.requestFocus(); } }); - setTextInCardEditorAndWait(new String[] {"3782 822463 10005 1"}, getEditorTextUpdate()); - assertTrue(getCardEditorFocusedView() == focusedChildView); + mPaymentRequestTestRule.setTextInCardEditorAndWait(new String[] {"3782 822463 10005 1"}, + mPaymentRequestTestRule.getEditorTextUpdate()); + Assert.assertTrue(mPaymentRequestTestRule.getCardEditorFocusedView() == focusedChildView); } + @Test @MediumTest @Feature({"Payments"}) public void test16DigitsCreditCard() throws InterruptedException, ExecutionException, TimeoutException { - triggerUIAndWait(getReadyToPay()); + mPaymentRequestTestRule.triggerUIAndWait(mPaymentRequestTestRule.getReadyToPay()); - clickInPaymentMethodAndWait(R.id.payments_section, getReadyForInput()); - clickInPaymentMethodAndWait(R.id.payments_add_option_button, getReadyToEdit()); + mPaymentRequestTestRule.clickInPaymentMethodAndWait( + R.id.payments_section, mPaymentRequestTestRule.getReadyForInput()); + mPaymentRequestTestRule.clickInPaymentMethodAndWait( + R.id.payments_add_option_button, mPaymentRequestTestRule.getReadyToEdit()); // DISCOVER, JCB, MASTERCARD, MIR and VISA cards have 16 digits. Takes VISA as test input // which has 13 digits valid card. - final View focusedChildView = getCardEditorFocusedView(); - setTextInCardEditorAndWait(new String[] {"4012 8888 8888 "}, getEditorTextUpdate()); - assertTrue(getCardEditorFocusedView() == focusedChildView); + final View focusedChildView = mPaymentRequestTestRule.getCardEditorFocusedView(); + mPaymentRequestTestRule.setTextInCardEditorAndWait( + new String[] {"4012 8888 8888 "}, mPaymentRequestTestRule.getEditorTextUpdate()); + Assert.assertTrue(mPaymentRequestTestRule.getCardEditorFocusedView() == focusedChildView); // '4012 8888 8888 1' is a valid 13 digits card number. - setTextInCardEditorAndWait(new String[] {"4012 8888 8888 1"}, getEditorTextUpdate()); - assertTrue(getCardEditorFocusedView() == focusedChildView); + mPaymentRequestTestRule.setTextInCardEditorAndWait( + new String[] {"4012 8888 8888 1"}, mPaymentRequestTestRule.getEditorTextUpdate()); + Assert.assertTrue(mPaymentRequestTestRule.getCardEditorFocusedView() == focusedChildView); - setTextInCardEditorAndWait(new String[] {"4012 8888 8888 188"}, getEditorTextUpdate()); - assertTrue(getCardEditorFocusedView() == focusedChildView); + mPaymentRequestTestRule.setTextInCardEditorAndWait( + new String[] {"4012 8888 8888 188"}, mPaymentRequestTestRule.getEditorTextUpdate()); + Assert.assertTrue(mPaymentRequestTestRule.getCardEditorFocusedView() == focusedChildView); // '4012 8888 8888 1880' is an invalid 16 digits card number. - setTextInCardEditorAndWait(new String[] {"4012 8888 8888 1880"}, getEditorTextUpdate()); - assertTrue(getCardEditorFocusedView() == focusedChildView); + mPaymentRequestTestRule.setTextInCardEditorAndWait(new String[] {"4012 8888 8888 1880"}, + mPaymentRequestTestRule.getEditorTextUpdate()); + Assert.assertTrue(mPaymentRequestTestRule.getCardEditorFocusedView() == focusedChildView); // '4012 8888 8888 1881' is a valid 16 digits card number. - setTextInCardEditorAndWait(new String[] {"4012 8888 8888 1881"}, getEditorTextUpdate()); - assertTrue(getCardEditorFocusedView() != focusedChildView); + mPaymentRequestTestRule.setTextInCardEditorAndWait(new String[] {"4012 8888 8888 1881"}, + mPaymentRequestTestRule.getEditorTextUpdate()); + Assert.assertTrue(mPaymentRequestTestRule.getCardEditorFocusedView() != focusedChildView); // Request focus to card number field after auto advancing above. ThreadUtils.runOnUiThreadBlocking(new Runnable() { @@ -145,38 +182,47 @@ focusedChildView.requestFocus(); } }); - setTextInCardEditorAndWait(new String[] {"4012 8888 8888 1881 1"}, getEditorTextUpdate()); - assertTrue(getCardEditorFocusedView() == focusedChildView); + mPaymentRequestTestRule.setTextInCardEditorAndWait(new String[] {"4012 8888 8888 1881 1"}, + mPaymentRequestTestRule.getEditorTextUpdate()); + Assert.assertTrue(mPaymentRequestTestRule.getCardEditorFocusedView() == focusedChildView); } + @Test @MediumTest @Feature({"Payments"}) public void test19DigitsCreditCard() throws InterruptedException, ExecutionException, TimeoutException { - triggerUIAndWait(getReadyToPay()); + mPaymentRequestTestRule.triggerUIAndWait(mPaymentRequestTestRule.getReadyToPay()); - clickInPaymentMethodAndWait(R.id.payments_section, getReadyForInput()); - clickInPaymentMethodAndWait(R.id.payments_add_option_button, getReadyToEdit()); + mPaymentRequestTestRule.clickInPaymentMethodAndWait( + R.id.payments_section, mPaymentRequestTestRule.getReadyForInput()); + mPaymentRequestTestRule.clickInPaymentMethodAndWait( + R.id.payments_add_option_button, mPaymentRequestTestRule.getReadyToEdit()); // UNIONPAY credit card. - final View focusedChildView = getCardEditorFocusedView(); - setTextInCardEditorAndWait(new String[] {"6250 9410 0652 859"}, getEditorTextUpdate()); - assertTrue(getCardEditorFocusedView() == focusedChildView); + final View focusedChildView = mPaymentRequestTestRule.getCardEditorFocusedView(); + mPaymentRequestTestRule.setTextInCardEditorAndWait( + new String[] {"6250 9410 0652 859"}, mPaymentRequestTestRule.getEditorTextUpdate()); + Assert.assertTrue(mPaymentRequestTestRule.getCardEditorFocusedView() == focusedChildView); // '6250 9410 0652 8599' is a valid 16 digits card number. - setTextInCardEditorAndWait(new String[] {"6250 9410 0652 8599"}, getEditorTextUpdate()); - assertTrue(getCardEditorFocusedView() == focusedChildView); + mPaymentRequestTestRule.setTextInCardEditorAndWait(new String[] {"6250 9410 0652 8599"}, + mPaymentRequestTestRule.getEditorTextUpdate()); + Assert.assertTrue(mPaymentRequestTestRule.getCardEditorFocusedView() == focusedChildView); - setTextInCardEditorAndWait(new String[] {"6212 3456 7890 0000 00"}, getEditorTextUpdate()); - assertTrue(getCardEditorFocusedView() == focusedChildView); + mPaymentRequestTestRule.setTextInCardEditorAndWait(new String[] {"6212 3456 7890 0000 00"}, + mPaymentRequestTestRule.getEditorTextUpdate()); + Assert.assertTrue(mPaymentRequestTestRule.getCardEditorFocusedView() == focusedChildView); // '6212 3456 7890 0000 001' is an invalid 19 digits card number. - setTextInCardEditorAndWait(new String[] {"6212 3456 7890 0000 001"}, getEditorTextUpdate()); - assertTrue(getCardEditorFocusedView() == focusedChildView); + mPaymentRequestTestRule.setTextInCardEditorAndWait(new String[] {"6212 3456 7890 0000 001"}, + mPaymentRequestTestRule.getEditorTextUpdate()); + Assert.assertTrue(mPaymentRequestTestRule.getCardEditorFocusedView() == focusedChildView); // '6212 3456 7890 0000 003' is a valid 19 digits card number. - setTextInCardEditorAndWait(new String[] {"6212 3456 7890 0000 003"}, getEditorTextUpdate()); - assertTrue(getCardEditorFocusedView() != focusedChildView); + mPaymentRequestTestRule.setTextInCardEditorAndWait(new String[] {"6212 3456 7890 0000 003"}, + mPaymentRequestTestRule.getEditorTextUpdate()); + Assert.assertTrue(mPaymentRequestTestRule.getCardEditorFocusedView() != focusedChildView); // Request focus to card number field after auto advancing above. ThreadUtils.runOnUiThreadBlocking(new Runnable() { @@ -185,8 +231,9 @@ focusedChildView.requestFocus(); } }); - setTextInCardEditorAndWait( - new String[] {"6212 3456 7890 0000 0031"}, getEditorTextUpdate()); - assertTrue(getCardEditorFocusedView() == focusedChildView); + mPaymentRequestTestRule.setTextInCardEditorAndWait( + new String[] {"6212 3456 7890 0000 0031"}, + mPaymentRequestTestRule.getEditorTextUpdate()); + Assert.assertTrue(mPaymentRequestTestRule.getCardEditorFocusedView() == focusedChildView); } }
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestCcCanMakePaymentQueryNoCardTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestCcCanMakePaymentQueryNoCardTest.java index 65e7b99d..ba4bd4e 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestCcCanMakePaymentQueryNoCardTest.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestCcCanMakePaymentQueryNoCardTest.java
@@ -6,10 +6,19 @@ import android.support.test.filters.MediumTest; +import org.junit.Rule; +import org.junit.Test; +import org.junit.runner.RunWith; + +import org.chromium.base.test.util.CommandLineFlags; import org.chromium.base.test.util.Feature; import org.chromium.chrome.R; +import org.chromium.chrome.browser.ChromeSwitches; import org.chromium.chrome.browser.autofill.AutofillTestHelper; import org.chromium.chrome.browser.autofill.PersonalDataManager.CreditCard; +import org.chromium.chrome.browser.payments.PaymentRequestTestRule.MainActivityStartCallback; +import org.chromium.chrome.test.ChromeActivityTestRule; +import org.chromium.chrome.test.ChromeJUnit4ClassRunner; import java.util.concurrent.ExecutionException; import java.util.concurrent.TimeoutException; @@ -18,10 +27,15 @@ * A payment integration test for checking whether user can make a payment via a credit card. * This user does not have a complete credit card on file. */ -public class PaymentRequestCcCanMakePaymentQueryNoCardTest extends PaymentRequestTestBase { - public PaymentRequestCcCanMakePaymentQueryNoCardTest() { - super("payment_request_can_make_payment_query_cc_test.html"); - } +@RunWith(ChromeJUnit4ClassRunner.class) +@CommandLineFlags.Add({ + ChromeSwitches.DISABLE_FIRST_RUN_EXPERIENCE, + ChromeActivityTestRule.DISABLE_NETWORK_PREDICTION_FLAG, +}) +public class PaymentRequestCcCanMakePaymentQueryNoCardTest implements MainActivityStartCallback { + @Rule + public PaymentRequestTestRule mPaymentRequestTestRule = + new PaymentRequestTestRule("payment_request_can_make_payment_query_cc_test.html", this); @Override public void onMainActivityStarted() throws InterruptedException, ExecutionException, @@ -33,11 +47,13 @@ R.drawable.pr_visa, "" /* billingAddressId */, "" /* serverId */)); } + @Test @MediumTest @Feature({"Payments"}) - public void testCannotMakePayment() throws InterruptedException, ExecutionException, - TimeoutException { - openPageAndClickBuyAndWait(getCanMakePaymentQueryResponded()); - expectResultContains(new String[]{"false"}); + public void testCannotMakePayment() + throws InterruptedException, ExecutionException, TimeoutException { + mPaymentRequestTestRule.openPageAndClickBuyAndWait( + mPaymentRequestTestRule.getCanMakePaymentQueryResponded()); + mPaymentRequestTestRule.expectResultContains(new String[] {"false"}); } }
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestContactDetailsAndFreeShippingTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestContactDetailsAndFreeShippingTest.java index 2a06e94..98b2821 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestContactDetailsAndFreeShippingTest.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestContactDetailsAndFreeShippingTest.java
@@ -7,12 +7,22 @@ import android.content.DialogInterface; import android.support.test.filters.MediumTest; +import org.junit.Assert; +import org.junit.Rule; +import org.junit.Test; +import org.junit.runner.RunWith; + import org.chromium.base.metrics.RecordHistogram; +import org.chromium.base.test.util.CommandLineFlags; import org.chromium.base.test.util.Feature; import org.chromium.chrome.R; +import org.chromium.chrome.browser.ChromeSwitches; import org.chromium.chrome.browser.autofill.AutofillTestHelper; import org.chromium.chrome.browser.autofill.PersonalDataManager.AutofillProfile; import org.chromium.chrome.browser.autofill.PersonalDataManager.CreditCard; +import org.chromium.chrome.browser.payments.PaymentRequestTestRule.MainActivityStartCallback; +import org.chromium.chrome.test.ChromeActivityTestRule; +import org.chromium.chrome.test.ChromeJUnit4ClassRunner; import java.util.concurrent.ExecutionException; import java.util.concurrent.TimeoutException; @@ -21,12 +31,15 @@ * A payment integration test for a merchant that requests a payer name, an email address and * a phone number and provides free shipping regardless of address. */ -public class PaymentRequestContactDetailsAndFreeShippingTest extends PaymentRequestTestBase { - public PaymentRequestContactDetailsAndFreeShippingTest() { - // This merchant requests an email address and a phone number and provides free shipping - // worldwide. - super("payment_request_contact_details_and_free_shipping_test.html"); - } +@RunWith(ChromeJUnit4ClassRunner.class) +@CommandLineFlags.Add({ + ChromeSwitches.DISABLE_FIRST_RUN_EXPERIENCE, + ChromeActivityTestRule.DISABLE_NETWORK_PREDICTION_FLAG, +}) +public class PaymentRequestContactDetailsAndFreeShippingTest implements MainActivityStartCallback { + @Rule + public PaymentRequestTestRule mPaymentRequestTestRule = new PaymentRequestTestRule( + "payment_request_contact_details_and_free_shipping_test.html", this); @Override public void onMainActivityStarted() @@ -46,16 +59,21 @@ * Submit the payer name, email address, phone number and shipping address to the merchant when * the user clicks "Pay." */ + @Test @MediumTest @Feature({"Payments"}) public void testPay() throws InterruptedException, ExecutionException, TimeoutException { - triggerUIAndWait(getReadyToPay()); - clickAndWait(R.id.button_primary, getReadyForUnmaskInput()); - setTextInCardUnmaskDialogAndWait(R.id.card_unmask_input, "123", getReadyToUnmask()); - clickCardUnmaskButtonAndWait(DialogInterface.BUTTON_POSITIVE, getDismissed()); - expectResultContains(new String[] {"Jon Doe", "jon.doe@google.com", "+15555555555", - "Jon Doe", "4111111111111111", "12", "2050", "visa", "123", "Google", "340 Main St", - "CA", "Los Angeles", "90291", "US", "en", "freeShippingOption"}); + mPaymentRequestTestRule.triggerUIAndWait(mPaymentRequestTestRule.getReadyToPay()); + mPaymentRequestTestRule.clickAndWait( + R.id.button_primary, mPaymentRequestTestRule.getReadyForUnmaskInput()); + mPaymentRequestTestRule.setTextInCardUnmaskDialogAndWait( + R.id.card_unmask_input, "123", mPaymentRequestTestRule.getReadyToUnmask()); + mPaymentRequestTestRule.clickCardUnmaskButtonAndWait( + DialogInterface.BUTTON_POSITIVE, mPaymentRequestTestRule.getDismissed()); + mPaymentRequestTestRule.expectResultContains( + new String[] {"Jon Doe", "jon.doe@google.com", "+15555555555", "Jon Doe", + "4111111111111111", "12", "2050", "visa", "123", "Google", "340 Main St", + "CA", "Los Angeles", "90291", "US", "en", "freeShippingOption"}); } /** @@ -63,19 +81,27 @@ * and a shipping address results in the appropriate metric being logged in the * PaymentRequest.RequestedInformation histogram. */ + @Test @MediumTest @Feature({"Payments"}) - public void testRequestedInformationMetric() throws InterruptedException, ExecutionException, - TimeoutException { + public void testRequestedInformationMetric() + throws InterruptedException, ExecutionException, TimeoutException { // Start the Payment Request. - triggerUIAndWait(getReadyToPay()); + mPaymentRequestTestRule.triggerUIAndWait(mPaymentRequestTestRule.getReadyToPay()); // Make sure that only the appropriate enum value was logged. for (int i = 0; i < PaymentRequestMetrics.REQUESTED_INFORMATION_MAX; ++i) { - assertEquals((i == (PaymentRequestMetrics.REQUESTED_INFORMATION_EMAIL - | PaymentRequestMetrics.REQUESTED_INFORMATION_PHONE - | PaymentRequestMetrics.REQUESTED_INFORMATION_SHIPPING - | PaymentRequestMetrics.REQUESTED_INFORMATION_NAME) ? 1 : 0), + Assert.assertEquals( + (i + == (PaymentRequestMetrics.REQUESTED_INFORMATION_EMAIL + | PaymentRequestMetrics + .REQUESTED_INFORMATION_PHONE + | PaymentRequestMetrics + .REQUESTED_INFORMATION_SHIPPING + | PaymentRequestMetrics + .REQUESTED_INFORMATION_NAME) + ? 1 + : 0), RecordHistogram.getHistogramValueCountForTesting( "PaymentRequest.RequestedInformation", i)); }
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestContactDetailsTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestContactDetailsTest.java index 92d772f9f..b786557 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestContactDetailsTest.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestContactDetailsTest.java
@@ -4,14 +4,27 @@ package org.chromium.chrome.browser.payments; +import static org.chromium.chrome.browser.payments.PaymentRequestTestRule.HAVE_INSTRUMENTS; +import static org.chromium.chrome.browser.payments.PaymentRequestTestRule.IMMEDIATE_RESPONSE; + import android.support.test.filters.MediumTest; +import org.junit.Assert; +import org.junit.Rule; +import org.junit.Test; +import org.junit.runner.RunWith; + import org.chromium.base.ThreadUtils; import org.chromium.base.metrics.RecordHistogram; +import org.chromium.base.test.util.CommandLineFlags; import org.chromium.base.test.util.Feature; import org.chromium.chrome.R; +import org.chromium.chrome.browser.ChromeSwitches; import org.chromium.chrome.browser.autofill.AutofillTestHelper; import org.chromium.chrome.browser.autofill.PersonalDataManager.AutofillProfile; +import org.chromium.chrome.browser.payments.PaymentRequestTestRule.MainActivityStartCallback; +import org.chromium.chrome.test.ChromeActivityTestRule; +import org.chromium.chrome.test.ChromeJUnit4ClassRunner; import java.util.concurrent.ExecutionException; import java.util.concurrent.TimeoutException; @@ -19,11 +32,15 @@ /** * A payment integration test for a merchant that requests contact details. */ -public class PaymentRequestContactDetailsTest extends PaymentRequestTestBase { - public PaymentRequestContactDetailsTest() { - // The merchant requests a payer name, a phone number and an email address. - super("payment_request_contact_details_test.html"); - } +@RunWith(ChromeJUnit4ClassRunner.class) +@CommandLineFlags.Add({ + ChromeSwitches.DISABLE_FIRST_RUN_EXPERIENCE, + ChromeActivityTestRule.DISABLE_NETWORK_PREDICTION_FLAG, +}) +public class PaymentRequestContactDetailsTest implements MainActivityStartCallback { + @Rule + public PaymentRequestTestRule mPaymentRequestTestRule = + new PaymentRequestTestRule("payment_request_contact_details_test.html", this); @Override public void onMainActivityStarted() @@ -54,210 +71,249 @@ "Google", "340 Main St", "CA", "Los Angeles", "", "90291", "", "US", "555-555-5555", "jon.doe@google.com", "en-US")); - installPaymentApp(HAVE_INSTRUMENTS, IMMEDIATE_RESPONSE); + mPaymentRequestTestRule.installPaymentApp(HAVE_INSTRUMENTS, IMMEDIATE_RESPONSE); } /** Provide the existing valid payer name, phone number and email address to the merchant. */ + @Test @MediumTest @Feature({"Payments"}) public void testPay() throws InterruptedException, ExecutionException, TimeoutException { - triggerUIAndWait(getReadyToPay()); - clickAndWait(R.id.button_primary, getDismissed()); - expectResultContains(new String[] {"Jon Doe", "+15555555555", "jon.doe@google.com"}); + mPaymentRequestTestRule.triggerUIAndWait(mPaymentRequestTestRule.getReadyToPay()); + mPaymentRequestTestRule.clickAndWait( + R.id.button_primary, mPaymentRequestTestRule.getDismissed()); + mPaymentRequestTestRule.expectResultContains( + new String[] {"Jon Doe", "+15555555555", "jon.doe@google.com"}); } /** Attempt to add invalid contact information and cancel the transaction. */ + @Test @MediumTest @Feature({"Payments"}) public void testAddInvalidContactAndCancel() throws InterruptedException, ExecutionException, TimeoutException { - triggerUIAndWait(getReadyToPay()); - clickInContactInfoAndWait(R.id.payments_section, getReadyForInput()); - clickInContactInfoAndWait(R.id.payments_add_option_button, getReadyToEdit()); - setTextInEditorAndWait(new String[] {"", "+++", "jane.jones"}, getEditorTextUpdate()); - clickInEditorAndWait(R.id.payments_edit_done_button, getEditorValidationError()); - clickInEditorAndWait(R.id.payments_edit_cancel_button, getReadyToPay()); - clickAndWait(R.id.close_button, getDismissed()); - expectResultContains(new String[] {"Request cancelled"}); + mPaymentRequestTestRule.triggerUIAndWait(mPaymentRequestTestRule.getReadyToPay()); + mPaymentRequestTestRule.clickInContactInfoAndWait( + R.id.payments_section, mPaymentRequestTestRule.getReadyForInput()); + mPaymentRequestTestRule.clickInContactInfoAndWait( + R.id.payments_add_option_button, mPaymentRequestTestRule.getReadyToEdit()); + mPaymentRequestTestRule.setTextInEditorAndWait(new String[] {"", "+++", "jane.jones"}, + mPaymentRequestTestRule.getEditorTextUpdate()); + mPaymentRequestTestRule.clickInEditorAndWait( + R.id.payments_edit_done_button, mPaymentRequestTestRule.getEditorValidationError()); + mPaymentRequestTestRule.clickInEditorAndWait( + R.id.payments_edit_cancel_button, mPaymentRequestTestRule.getReadyToPay()); + mPaymentRequestTestRule.clickAndWait( + R.id.close_button, mPaymentRequestTestRule.getDismissed()); + mPaymentRequestTestRule.expectResultContains(new String[] {"Request cancelled"}); } /** Add new payer name, phone number and email address and provide that to the merchant. */ + @Test @MediumTest @Feature({"Payments"}) public void testAddContactAndPay() throws InterruptedException, ExecutionException, TimeoutException { - triggerUIAndWait(getReadyToPay()); - clickInContactInfoAndWait(R.id.payments_section, getReadyForInput()); - clickInContactInfoAndWait(R.id.payments_add_option_button, getReadyToEdit()); - setTextInEditorAndWait(new String[] {"Jane Jones", "999-999-9999", "jane.jones@google.com"}, - getEditorTextUpdate()); - clickInEditorAndWait(R.id.payments_edit_done_button, getReadyToPay()); + mPaymentRequestTestRule.triggerUIAndWait(mPaymentRequestTestRule.getReadyToPay()); + mPaymentRequestTestRule.clickInContactInfoAndWait( + R.id.payments_section, mPaymentRequestTestRule.getReadyForInput()); + mPaymentRequestTestRule.clickInContactInfoAndWait( + R.id.payments_add_option_button, mPaymentRequestTestRule.getReadyToEdit()); + mPaymentRequestTestRule.setTextInEditorAndWait( + new String[] {"Jane Jones", "999-999-9999", "jane.jones@google.com"}, + mPaymentRequestTestRule.getEditorTextUpdate()); + mPaymentRequestTestRule.clickInEditorAndWait( + R.id.payments_edit_done_button, mPaymentRequestTestRule.getReadyToPay()); - clickAndWait(R.id.button_primary, getDismissed()); - expectResultContains(new String[] {"Jane Jones", "+19999999999", "jane.jones@google.com"}); + mPaymentRequestTestRule.clickAndWait( + R.id.button_primary, mPaymentRequestTestRule.getDismissed()); + mPaymentRequestTestRule.expectResultContains( + new String[] {"Jane Jones", "+19999999999", "jane.jones@google.com"}); } /** Quickly pressing on "add contact info" and then [X] should not crash. */ + @Test @MediumTest @Feature({"Payments"}) public void testQuickAddContactAndCloseShouldNotCrash() throws InterruptedException, ExecutionException, TimeoutException { - triggerUIAndWait(getReadyToPay()); - clickInContactInfoAndWait(R.id.payments_section, getReadyForInput()); + mPaymentRequestTestRule.triggerUIAndWait(mPaymentRequestTestRule.getReadyToPay()); + mPaymentRequestTestRule.clickInContactInfoAndWait( + R.id.payments_section, mPaymentRequestTestRule.getReadyForInput()); // Quickly press on "add contact info" and then [X]. - int callCount = getReadyToEdit().getCallCount(); + int callCount = mPaymentRequestTestRule.getReadyToEdit().getCallCount(); ThreadUtils.runOnUiThreadBlocking(new Runnable() { @Override public void run() { - getPaymentRequestUI() + mPaymentRequestTestRule.getPaymentRequestUI() .getContactDetailsSectionForTest() .findViewById(R.id.payments_add_option_button) .performClick(); - getPaymentRequestUI() + mPaymentRequestTestRule.getPaymentRequestUI() .getDialogForTest() .findViewById(R.id.close_button) .performClick(); } }); - getReadyToEdit().waitForCallback(callCount); + mPaymentRequestTestRule.getReadyToEdit().waitForCallback(callCount); - clickInEditorAndWait(R.id.payments_edit_cancel_button, getReadyToPay()); - clickAndWait(R.id.close_button, getDismissed()); - expectResultContains(new String[] {"Request cancelled"}); + mPaymentRequestTestRule.clickInEditorAndWait( + R.id.payments_edit_cancel_button, mPaymentRequestTestRule.getReadyToPay()); + mPaymentRequestTestRule.clickAndWait( + R.id.close_button, mPaymentRequestTestRule.getDismissed()); + mPaymentRequestTestRule.expectResultContains(new String[] {"Request cancelled"}); } /** Quickly pressing on [X] and then "add contact info" should not crash. */ + @Test @MediumTest @Feature({"Payments"}) public void testQuickCloseAndAddContactShouldNotCrash() throws InterruptedException, ExecutionException, TimeoutException { - triggerUIAndWait(getReadyToPay()); - clickInContactInfoAndWait(R.id.payments_section, getReadyForInput()); + mPaymentRequestTestRule.triggerUIAndWait(mPaymentRequestTestRule.getReadyToPay()); + mPaymentRequestTestRule.clickInContactInfoAndWait( + R.id.payments_section, mPaymentRequestTestRule.getReadyForInput()); // Quickly press on [X] and then "add contact info." - int callCount = getDismissed().getCallCount(); + int callCount = mPaymentRequestTestRule.getDismissed().getCallCount(); ThreadUtils.runOnUiThreadBlocking(new Runnable() { @Override public void run() { - getPaymentRequestUI() + mPaymentRequestTestRule.getPaymentRequestUI() .getDialogForTest() .findViewById(R.id.close_button) .performClick(); - getPaymentRequestUI() + mPaymentRequestTestRule.getPaymentRequestUI() .getContactDetailsSectionForTest() .findViewById(R.id.payments_add_option_button) .performClick(); } }); - getDismissed().waitForCallback(callCount); + mPaymentRequestTestRule.getDismissed().waitForCallback(callCount); - expectResultContains(new String[] {"Request cancelled"}); + mPaymentRequestTestRule.expectResultContains(new String[] {"Request cancelled"}); } /** Test that going into the editor and cancelling will leave the row checked. */ + @Test @MediumTest @Feature({"Payments"}) public void testEditContactAndCancelEditorShouldKeepContactSelected() throws InterruptedException, ExecutionException, TimeoutException { - triggerUIAndWait(getReadyToPay()); - clickInContactInfoAndWait(R.id.payments_section, getReadyForInput()); - expectContactDetailsRowIsSelected(0); - clickInContactInfoAndWait(R.id.payments_open_editor_pencil_button, getReadyToEdit()); + mPaymentRequestTestRule.triggerUIAndWait(mPaymentRequestTestRule.getReadyToPay()); + mPaymentRequestTestRule.clickInContactInfoAndWait( + R.id.payments_section, mPaymentRequestTestRule.getReadyForInput()); + mPaymentRequestTestRule.expectContactDetailsRowIsSelected(0); + mPaymentRequestTestRule.clickInContactInfoAndWait( + R.id.payments_open_editor_pencil_button, mPaymentRequestTestRule.getReadyToEdit()); // Cancel the editor. - clickInEditorAndWait(R.id.payments_edit_cancel_button, getReadyToPay()); + mPaymentRequestTestRule.clickInEditorAndWait( + R.id.payments_edit_cancel_button, mPaymentRequestTestRule.getReadyToPay()); // Expect the row to still be selected in the Contact Details section. - expectContactDetailsRowIsSelected(0); + mPaymentRequestTestRule.expectContactDetailsRowIsSelected(0); } /** Test that going into the "add" flow and cancelling will leave existing row checked. */ + @Test @MediumTest @Feature({"Payments"}) public void testAddContactAndCancelEditorShouldKeepContactSelected() throws InterruptedException, ExecutionException, TimeoutException { - triggerUIAndWait(getReadyToPay()); - clickInContactInfoAndWait(R.id.payments_section, getReadyForInput()); - expectContactDetailsRowIsSelected(0); - clickInContactInfoAndWait(R.id.payments_add_option_button, getReadyToEdit()); + mPaymentRequestTestRule.triggerUIAndWait(mPaymentRequestTestRule.getReadyToPay()); + mPaymentRequestTestRule.clickInContactInfoAndWait( + R.id.payments_section, mPaymentRequestTestRule.getReadyForInput()); + mPaymentRequestTestRule.expectContactDetailsRowIsSelected(0); + mPaymentRequestTestRule.clickInContactInfoAndWait( + R.id.payments_add_option_button, mPaymentRequestTestRule.getReadyToEdit()); // Cancel the editor. - clickInEditorAndWait(R.id.payments_edit_cancel_button, getReadyToPay()); + mPaymentRequestTestRule.clickInEditorAndWait( + R.id.payments_edit_cancel_button, mPaymentRequestTestRule.getReadyToPay()); // Expect the existing row to still be selected in the Contact Details section. - expectContactDetailsRowIsSelected(0); + mPaymentRequestTestRule.expectContactDetailsRowIsSelected(0); } /** Quickly pressing on "add contact info" and then "cancel" should not crash. */ + @Test @MediumTest @Feature({"Payments"}) public void testQuickAddContactAndCancelShouldNotCrash() throws InterruptedException, ExecutionException, TimeoutException { - triggerUIAndWait(getReadyToPay()); - clickInContactInfoAndWait(R.id.payments_section, getReadyForInput()); + mPaymentRequestTestRule.triggerUIAndWait(mPaymentRequestTestRule.getReadyToPay()); + mPaymentRequestTestRule.clickInContactInfoAndWait( + R.id.payments_section, mPaymentRequestTestRule.getReadyForInput()); // Quickly press on "add contact info" and then "cancel." - int callCount = getReadyToEdit().getCallCount(); + int callCount = mPaymentRequestTestRule.getReadyToEdit().getCallCount(); ThreadUtils.runOnUiThreadBlocking(new Runnable() { @Override public void run() { - getPaymentRequestUI() + mPaymentRequestTestRule.getPaymentRequestUI() .getContactDetailsSectionForTest() .findViewById(R.id.payments_add_option_button) .performClick(); - getPaymentRequestUI() + mPaymentRequestTestRule.getPaymentRequestUI() .getDialogForTest() .findViewById(R.id.button_secondary) .performClick(); } }); - getReadyToEdit().waitForCallback(callCount); + mPaymentRequestTestRule.getReadyToEdit().waitForCallback(callCount); - clickInEditorAndWait(R.id.payments_edit_cancel_button, getReadyToPay()); - clickAndWait(R.id.close_button, getDismissed()); - expectResultContains(new String[] {"Request cancelled"}); + mPaymentRequestTestRule.clickInEditorAndWait( + R.id.payments_edit_cancel_button, mPaymentRequestTestRule.getReadyToPay()); + mPaymentRequestTestRule.clickAndWait( + R.id.close_button, mPaymentRequestTestRule.getDismissed()); + mPaymentRequestTestRule.expectResultContains(new String[] {"Request cancelled"}); } /** Quickly pressing on "cancel" and then "add contact info" should not crash. */ + @Test @MediumTest @Feature({"Payments"}) public void testQuickCancelAndAddContactShouldNotCrash() throws InterruptedException, ExecutionException, TimeoutException { - triggerUIAndWait(getReadyToPay()); - clickInContactInfoAndWait(R.id.payments_section, getReadyForInput()); + mPaymentRequestTestRule.triggerUIAndWait(mPaymentRequestTestRule.getReadyToPay()); + mPaymentRequestTestRule.clickInContactInfoAndWait( + R.id.payments_section, mPaymentRequestTestRule.getReadyForInput()); // Quickly press on "cancel" and then "add contact info." - int callCount = getDismissed().getCallCount(); + int callCount = mPaymentRequestTestRule.getDismissed().getCallCount(); ThreadUtils.runOnUiThreadBlocking(new Runnable() { @Override public void run() { - getPaymentRequestUI() + mPaymentRequestTestRule.getPaymentRequestUI() .getDialogForTest() .findViewById(R.id.button_secondary) .performClick(); - getPaymentRequestUI() + mPaymentRequestTestRule.getPaymentRequestUI() .getContactDetailsSectionForTest() .findViewById(R.id.payments_add_option_button) .performClick(); } }); - getDismissed().waitForCallback(callCount); + mPaymentRequestTestRule.getDismissed().waitForCallback(callCount); - expectResultContains(new String[] {"Request cancelled"}); + mPaymentRequestTestRule.expectResultContains(new String[] {"Request cancelled"}); } /** * Makes sure that suggestions that are equal to or subsets of other suggestions are not shown * to the user. */ + @Test @MediumTest @Feature({"Payments"}) public void testSuggestionsDeduped() throws InterruptedException, ExecutionException, TimeoutException { - triggerUIAndWait(getReadyToPay()); - clickInContactInfoAndWait(R.id.payments_section, getReadyForInput()); - assertEquals(1, getNumberOfContactDetailSuggestions()); + mPaymentRequestTestRule.triggerUIAndWait(mPaymentRequestTestRule.getReadyToPay()); + mPaymentRequestTestRule.clickInContactInfoAndWait( + R.id.payments_section, mPaymentRequestTestRule.getReadyForInput()); + Assert.assertEquals(1, mPaymentRequestTestRule.getNumberOfContactDetailSuggestions()); } /** @@ -265,18 +321,25 @@ * name results in the appropriate metric being logged in the * PaymentRequest.RequestedInformation histogram. */ + @Test @MediumTest @Feature({"Payments"}) - public void testRequestedInformationMetric() throws InterruptedException, ExecutionException, - TimeoutException { + public void testRequestedInformationMetric() + throws InterruptedException, ExecutionException, TimeoutException { // Start the Payment Request. - triggerUIAndWait(getReadyToPay()); + mPaymentRequestTestRule.triggerUIAndWait(mPaymentRequestTestRule.getReadyToPay()); // Make sure that only the appropriate enum value was logged. for (int i = 0; i < PaymentRequestMetrics.REQUESTED_INFORMATION_MAX; ++i) { - assertEquals((i == (PaymentRequestMetrics.REQUESTED_INFORMATION_EMAIL - | PaymentRequestMetrics.REQUESTED_INFORMATION_PHONE - | PaymentRequestMetrics.REQUESTED_INFORMATION_NAME) ? 1 : 0), + Assert.assertEquals( + (i + == (PaymentRequestMetrics.REQUESTED_INFORMATION_EMAIL + | PaymentRequestMetrics + .REQUESTED_INFORMATION_PHONE + | PaymentRequestMetrics + .REQUESTED_INFORMATION_NAME) + ? 1 + : 0), RecordHistogram.getHistogramValueCountForTesting( "PaymentRequest.RequestedInformation", i)); }
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestDynamicShippingMultipleAddressesTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestDynamicShippingMultipleAddressesTest.java index cae5627..5ba62d3 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestDynamicShippingMultipleAddressesTest.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestDynamicShippingMultipleAddressesTest.java
@@ -6,10 +6,20 @@ import android.support.test.filters.MediumTest; +import org.junit.Assert; +import org.junit.Rule; +import org.junit.Test; +import org.junit.runner.RunWith; + +import org.chromium.base.test.util.CommandLineFlags; import org.chromium.base.test.util.Feature; import org.chromium.chrome.R; +import org.chromium.chrome.browser.ChromeSwitches; import org.chromium.chrome.browser.autofill.AutofillTestHelper; import org.chromium.chrome.browser.autofill.PersonalDataManager.AutofillProfile; +import org.chromium.chrome.browser.payments.PaymentRequestTestRule.MainActivityStartCallback; +import org.chromium.chrome.test.ChromeActivityTestRule; +import org.chromium.chrome.test.ChromeJUnit4ClassRunner; import java.util.ArrayList; import java.util.concurrent.ExecutionException; @@ -19,7 +29,17 @@ * A payment integration test for a merchant that requires shipping address to calculate shipping * and user that has 5 addresses stored in autofill settings. */ -public class PaymentRequestDynamicShippingMultipleAddressesTest extends PaymentRequestTestBase { +@RunWith(ChromeJUnit4ClassRunner.class) +@CommandLineFlags.Add({ + ChromeSwitches.DISABLE_FIRST_RUN_EXPERIENCE, + ChromeActivityTestRule.DISABLE_NETWORK_PREDICTION_FLAG, +}) +public class PaymentRequestDynamicShippingMultipleAddressesTest + implements MainActivityStartCallback { + @Rule + public PaymentRequestTestRule mPaymentRequestTestRule = + new PaymentRequestTestRule("payment_request_dynamic_shipping_test.html", this); + private static final AutofillProfile[] AUTOFILL_PROFILES = { // Incomplete profile (missing phone number) new AutofillProfile("" /* guid */, "https://www.example.com" /* origin */, @@ -61,11 +81,6 @@ private int[] mCountsToSet; private int[] mDatesToSet; - public PaymentRequestDynamicShippingMultipleAddressesTest() { - // This merchant requests the shipping address first before providing any shipping options. - super("payment_request_dynamic_shipping_test.html"); - } - @Override public void onMainActivityStarted() throws InterruptedException, ExecutionException, TimeoutException { @@ -88,6 +103,7 @@ * suggestions are shown. They should be ordered by frecency and complete addresses should be * suggested first. */ + @Test @MediumTest @Feature({"Payments"}) public void testShippingAddressSuggestionOrdering() @@ -100,18 +116,24 @@ mCountsToSet = new int[] {20, 15, 10, 5, 1}; mDatesToSet = new int[] {5000, 5000, 5000, 5000, 1}; - triggerUIAndWait(getReadyForInput()); - clickInShippingSummaryAndWait(R.id.payments_section, getReadyForInput()); - assertEquals(4, getNumberOfShippingAddressSuggestions()); - assertTrue(getShippingAddressSuggestionLabel(0).contains("Lisa Simpson")); - assertTrue(getShippingAddressSuggestionLabel(1).contains("Maggie Simpson")); - assertTrue(getShippingAddressSuggestionLabel(2).contains("Bart Simpson")); - assertTrue(getShippingAddressSuggestionLabel(3).contains("Marge Simpson")); + mPaymentRequestTestRule.triggerUIAndWait(mPaymentRequestTestRule.getReadyForInput()); + mPaymentRequestTestRule.clickInShippingSummaryAndWait( + R.id.payments_section, mPaymentRequestTestRule.getReadyForInput()); + Assert.assertEquals(4, mPaymentRequestTestRule.getNumberOfShippingAddressSuggestions()); + Assert.assertTrue(mPaymentRequestTestRule.getShippingAddressSuggestionLabel(0).contains( + "Lisa Simpson")); + Assert.assertTrue(mPaymentRequestTestRule.getShippingAddressSuggestionLabel(1).contains( + "Maggie Simpson")); + Assert.assertTrue(mPaymentRequestTestRule.getShippingAddressSuggestionLabel(2).contains( + "Bart Simpson")); + Assert.assertTrue(mPaymentRequestTestRule.getShippingAddressSuggestionLabel(3).contains( + "Marge Simpson")); } /** * Make sure that a maximum of four profiles are shown to the user. */ + @Test @MediumTest @Feature({"Payments"}) public void testShippingAddressSuggestionLimit() @@ -123,19 +145,25 @@ mCountsToSet = new int[] {20, 15, 10, 5, 2, 1}; mDatesToSet = new int[] {5000, 5000, 5000, 5000, 2, 1}; - triggerUIAndWait(getReadyForInput()); - clickInShippingSummaryAndWait(R.id.payments_section, getReadyForInput()); + mPaymentRequestTestRule.triggerUIAndWait(mPaymentRequestTestRule.getReadyForInput()); + mPaymentRequestTestRule.clickInShippingSummaryAndWait( + R.id.payments_section, mPaymentRequestTestRule.getReadyForInput()); // Only four profiles should be suggested to the user. - assertEquals(4, getNumberOfShippingAddressSuggestions()); - assertTrue(getShippingAddressSuggestionLabel(0).contains("Lisa Simpson")); - assertTrue(getShippingAddressSuggestionLabel(1).contains("Maggie Simpson")); - assertTrue(getShippingAddressSuggestionLabel(2).contains("Bart Simpson")); - assertTrue(getShippingAddressSuggestionLabel(3).contains("Marge Simpson")); + Assert.assertEquals(4, mPaymentRequestTestRule.getNumberOfShippingAddressSuggestions()); + Assert.assertTrue(mPaymentRequestTestRule.getShippingAddressSuggestionLabel(0).contains( + "Lisa Simpson")); + Assert.assertTrue(mPaymentRequestTestRule.getShippingAddressSuggestionLabel(1).contains( + "Maggie Simpson")); + Assert.assertTrue(mPaymentRequestTestRule.getShippingAddressSuggestionLabel(2).contains( + "Bart Simpson")); + Assert.assertTrue(mPaymentRequestTestRule.getShippingAddressSuggestionLabel(3).contains( + "Marge Simpson")); } /** * Make sure that only profiles with a street address are suggested to the user. */ + @Test @MediumTest @Feature({"Payments"}) public void testShippingAddressSuggestion_OnlyIncludeProfilesWithStreetAddress() @@ -148,20 +176,25 @@ mCountsToSet = new int[] {15, 10, 5, 1}; mDatesToSet = new int[] {5000, 5000, 5000, 1}; - triggerUIAndWait(getReadyForInput()); - clickInShippingSummaryAndWait(R.id.payments_section, getReadyForInput()); + mPaymentRequestTestRule.triggerUIAndWait(mPaymentRequestTestRule.getReadyForInput()); + mPaymentRequestTestRule.clickInShippingSummaryAndWait( + R.id.payments_section, mPaymentRequestTestRule.getReadyForInput()); // Only 3 profiles should be suggested, the two complete ones and the incomplete one that // has a street address. - assertEquals(3, getNumberOfShippingAddressSuggestions()); - assertTrue(getShippingAddressSuggestionLabel(0).contains("Lisa Simpson")); - assertTrue(getShippingAddressSuggestionLabel(1).contains("Maggie Simpson")); - assertTrue(getShippingAddressSuggestionLabel(2).contains("Bart Simpson")); + Assert.assertEquals(3, mPaymentRequestTestRule.getNumberOfShippingAddressSuggestions()); + Assert.assertTrue(mPaymentRequestTestRule.getShippingAddressSuggestionLabel(0).contains( + "Lisa Simpson")); + Assert.assertTrue(mPaymentRequestTestRule.getShippingAddressSuggestionLabel(1).contains( + "Maggie Simpson")); + Assert.assertTrue(mPaymentRequestTestRule.getShippingAddressSuggestionLabel(2).contains( + "Bart Simpson")); } /** * Select a shipping address that the website refuses to accept, which should force the dialog * to show an error. */ + @Test @MediumTest @Feature({"Payments"}) public void testShippingAddresNotAcceptedByMerchant() @@ -172,21 +205,25 @@ mDatesToSet = new int[] {5000}; // Click on the unacceptable shipping address. - triggerUIAndWait(getReadyForInput()); - clickInShippingSummaryAndWait(R.id.payments_section, getReadyForInput()); - assertTrue(getShippingAddressSuggestionLabel(0).contains( + mPaymentRequestTestRule.triggerUIAndWait(mPaymentRequestTestRule.getReadyForInput()); + mPaymentRequestTestRule.clickInShippingSummaryAndWait( + R.id.payments_section, mPaymentRequestTestRule.getReadyForInput()); + Assert.assertTrue(mPaymentRequestTestRule.getShippingAddressSuggestionLabel(0).contains( AUTOFILL_PROFILES[3].getFullName())); - clickOnShippingAddressSuggestionOptionAndWait(0, getSelectionChecked()); + mPaymentRequestTestRule.clickOnShippingAddressSuggestionOptionAndWait( + 0, mPaymentRequestTestRule.getSelectionChecked()); // The string should reflect the error sent from the merchant. - CharSequence actualString = getShippingAddressOptionRowAtIndex(0).getLabelText(); - assertEquals("We do not ship to this address", actualString); + CharSequence actualString = + mPaymentRequestTestRule.getShippingAddressOptionRowAtIndex(0).getLabelText(); + Assert.assertEquals("We do not ship to this address", actualString); } /** * Make sure the information required message has been displayed for incomplete profile * correctly. */ + @Test @MediumTest @Feature({"Payments"}) public void testShippingAddressEditRequiredMessage() @@ -197,13 +234,18 @@ mCountsToSet = new int[] {15, 10, 5, 1}; mDatesToSet = new int[] {5000, 5000, 5000, 1}; - triggerUIAndWait(getReadyForInput()); - clickInShippingSummaryAndWait(R.id.payments_section, getReadyForInput()); + mPaymentRequestTestRule.triggerUIAndWait(mPaymentRequestTestRule.getReadyForInput()); + mPaymentRequestTestRule.clickInShippingSummaryAndWait( + R.id.payments_section, mPaymentRequestTestRule.getReadyForInput()); - assertEquals(4, getNumberOfShippingAddressSuggestions()); - assertTrue(getShippingAddressSuggestionLabel(0).contains("Phone number required")); - assertTrue(getShippingAddressSuggestionLabel(1).contains("Enter a valid address")); - assertTrue(getShippingAddressSuggestionLabel(2).contains("Name required")); - assertTrue(getShippingAddressSuggestionLabel(3).contains("More information required")); + Assert.assertEquals(4, mPaymentRequestTestRule.getNumberOfShippingAddressSuggestions()); + Assert.assertTrue(mPaymentRequestTestRule.getShippingAddressSuggestionLabel(0).contains( + "Phone number required")); + Assert.assertTrue(mPaymentRequestTestRule.getShippingAddressSuggestionLabel(1).contains( + "Enter a valid address")); + Assert.assertTrue(mPaymentRequestTestRule.getShippingAddressSuggestionLabel(2).contains( + "Name required")); + Assert.assertTrue(mPaymentRequestTestRule.getShippingAddressSuggestionLabel(3).contains( + "More information required")); } }
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestDynamicShippingSingleAddressTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestDynamicShippingSingleAddressTest.java index 14cff02..539f284 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestDynamicShippingSingleAddressTest.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestDynamicShippingSingleAddressTest.java
@@ -7,14 +7,24 @@ import android.content.DialogInterface; import android.support.test.filters.MediumTest; +import org.junit.Assert; +import org.junit.Rule; +import org.junit.Test; +import org.junit.runner.RunWith; + import org.chromium.base.ThreadUtils; +import org.chromium.base.test.util.CommandLineFlags; import org.chromium.base.test.util.Feature; import org.chromium.base.test.util.FlakyTest; import org.chromium.chrome.R; +import org.chromium.chrome.browser.ChromeSwitches; import org.chromium.chrome.browser.autofill.AutofillTestHelper; import org.chromium.chrome.browser.autofill.PersonalDataManager.AutofillProfile; import org.chromium.chrome.browser.autofill.PersonalDataManager.CreditCard; +import org.chromium.chrome.browser.payments.PaymentRequestTestRule.MainActivityStartCallback; import org.chromium.chrome.browser.payments.ui.PaymentRequestSection; +import org.chromium.chrome.test.ChromeActivityTestRule; +import org.chromium.chrome.test.ChromeJUnit4ClassRunner; import java.util.concurrent.ExecutionException; import java.util.concurrent.TimeoutException; @@ -23,11 +33,15 @@ * A payment integration test for a merchant that requires shipping address to calculate shipping * and user that has a single address stored in autofill settings. */ -public class PaymentRequestDynamicShippingSingleAddressTest extends PaymentRequestTestBase { - public PaymentRequestDynamicShippingSingleAddressTest() { - // This merchant requests the shipping address first before providing any shipping options. - super("payment_request_dynamic_shipping_test.html"); - } +@RunWith(ChromeJUnit4ClassRunner.class) +@CommandLineFlags.Add({ + ChromeSwitches.DISABLE_FIRST_RUN_EXPERIENCE, + ChromeActivityTestRule.DISABLE_NETWORK_PREDICTION_FLAG, +}) +public class PaymentRequestDynamicShippingSingleAddressTest implements MainActivityStartCallback { + @Rule + public PaymentRequestTestRule mPaymentRequestTestRule = + new PaymentRequestTestRule("payment_request_dynamic_shipping_test.html", this); @Override public void onMainActivityStarted() @@ -43,100 +57,132 @@ } /** The shipping address should not be selected in UI by default. */ + @Test @MediumTest @Feature({"Payments"}) public void testAddressNotSelected() throws InterruptedException, ExecutionException, TimeoutException { - triggerUIAndWait(getReadyForInput()); - assertEquals(PaymentRequestSection.EDIT_BUTTON_CHOOSE, getSummarySectionButtonState()); + mPaymentRequestTestRule.triggerUIAndWait(mPaymentRequestTestRule.getReadyForInput()); + Assert.assertEquals(PaymentRequestSection.EDIT_BUTTON_CHOOSE, + mPaymentRequestTestRule.getSummarySectionButtonState()); } /** Expand the shipping address section, select an address, and click "Pay." */ + @Test @MediumTest @Feature({"Payments"}) public void testSelectValidAddressAndPay() throws InterruptedException, ExecutionException, TimeoutException { - triggerUIAndWait(getReadyForInput()); + mPaymentRequestTestRule.triggerUIAndWait(mPaymentRequestTestRule.getReadyForInput()); // Check that there is a selected payment method (makes sure we are not ready to pay because // of the Shipping Address). - expectPaymentMethodRowIsSelected(0); - clickInShippingSummaryAndWait(R.id.payments_section, getReadyForInput()); - clickInShippingAddressAndWait(R.id.payments_first_radio_button, getReadyToPay()); - clickAndWait(R.id.button_primary, getReadyForUnmaskInput()); - setTextInCardUnmaskDialogAndWait(R.id.card_unmask_input, "123", getReadyToUnmask()); - clickCardUnmaskButtonAndWait(DialogInterface.BUTTON_POSITIVE, getDismissed()); - expectResultContains(new String[] {"Jon Doe", "4111111111111111", "12", "2050", "visa", - "123", "Google", "340 Main St", "CA", "Los Angeles", "90291", "+16502530000", "US", - "en", "californiaShippingOption"}); + mPaymentRequestTestRule.expectPaymentMethodRowIsSelected(0); + mPaymentRequestTestRule.clickInShippingSummaryAndWait( + R.id.payments_section, mPaymentRequestTestRule.getReadyForInput()); + mPaymentRequestTestRule.clickInShippingAddressAndWait( + R.id.payments_first_radio_button, mPaymentRequestTestRule.getReadyToPay()); + mPaymentRequestTestRule.clickAndWait( + R.id.button_primary, mPaymentRequestTestRule.getReadyForUnmaskInput()); + mPaymentRequestTestRule.setTextInCardUnmaskDialogAndWait( + R.id.card_unmask_input, "123", mPaymentRequestTestRule.getReadyToUnmask()); + mPaymentRequestTestRule.clickCardUnmaskButtonAndWait( + DialogInterface.BUTTON_POSITIVE, mPaymentRequestTestRule.getDismissed()); + mPaymentRequestTestRule.expectResultContains(new String[] {"Jon Doe", "4111111111111111", + "12", "2050", "visa", "123", "Google", "340 Main St", "CA", "Los Angeles", "90291", + "+16502530000", "US", "en", "californiaShippingOption"}); } /** Expand the shipping address section, select an address, edit it and click "Pay." */ + @Test @MediumTest @Feature({"Payments"}) public void testSelectValidAddressEditItAndPay() throws InterruptedException, ExecutionException, TimeoutException { - triggerUIAndWait(getReadyForInput()); + mPaymentRequestTestRule.triggerUIAndWait(mPaymentRequestTestRule.getReadyForInput()); // Check that there is a selected payment method (makes sure we are not ready to pay because // of the Shipping Address). - expectPaymentMethodRowIsSelected(0); - clickInShippingSummaryAndWait(R.id.payments_section, getReadyForInput()); - clickInShippingAddressAndWait(R.id.payments_first_radio_button, getReadyToPay()); - expectShippingAddressRowIsSelected(0); - clickInShippingAddressAndWait(R.id.payments_open_editor_pencil_button, getReadyToEdit()); - setTextInEditorAndWait(new String[] {"Jane Doe"}, getEditorTextUpdate()); - clickInEditorAndWait(R.id.payments_edit_done_button, getReadyToPay()); - expectShippingAddressRowIsSelected(0); + mPaymentRequestTestRule.expectPaymentMethodRowIsSelected(0); + mPaymentRequestTestRule.clickInShippingSummaryAndWait( + R.id.payments_section, mPaymentRequestTestRule.getReadyForInput()); + mPaymentRequestTestRule.clickInShippingAddressAndWait( + R.id.payments_first_radio_button, mPaymentRequestTestRule.getReadyToPay()); + mPaymentRequestTestRule.expectShippingAddressRowIsSelected(0); + mPaymentRequestTestRule.clickInShippingAddressAndWait( + R.id.payments_open_editor_pencil_button, mPaymentRequestTestRule.getReadyToEdit()); + mPaymentRequestTestRule.setTextInEditorAndWait( + new String[] {"Jane Doe"}, mPaymentRequestTestRule.getEditorTextUpdate()); + mPaymentRequestTestRule.clickInEditorAndWait( + R.id.payments_edit_done_button, mPaymentRequestTestRule.getReadyToPay()); + mPaymentRequestTestRule.expectShippingAddressRowIsSelected(0); - clickAndWait(R.id.button_primary, getReadyForUnmaskInput()); - setTextInCardUnmaskDialogAndWait(R.id.card_unmask_input, "123", getReadyToUnmask()); - clickCardUnmaskButtonAndWait(DialogInterface.BUTTON_POSITIVE, getDismissed()); - expectResultContains(new String[] {"Jane Doe", "4111111111111111", "12", "2050", "visa", - "123", "Google", "340 Main St", "CA", "Los Angeles", "90291", "+16502530000", "US", - "en", "californiaShippingOption"}); + mPaymentRequestTestRule.clickAndWait( + R.id.button_primary, mPaymentRequestTestRule.getReadyForUnmaskInput()); + mPaymentRequestTestRule.setTextInCardUnmaskDialogAndWait( + R.id.card_unmask_input, "123", mPaymentRequestTestRule.getReadyToUnmask()); + mPaymentRequestTestRule.clickCardUnmaskButtonAndWait( + DialogInterface.BUTTON_POSITIVE, mPaymentRequestTestRule.getDismissed()); + mPaymentRequestTestRule.expectResultContains(new String[] {"Jane Doe", "4111111111111111", + "12", "2050", "visa", "123", "Google", "340 Main St", "CA", "Los Angeles", "90291", + "+16502530000", "US", "en", "californiaShippingOption"}); } /** Expand the shipping address section, select address, edit but cancel editing, and "Pay". */ + @Test @MediumTest @Feature({"Payments"}) public void testSelectValidAddressEditItAndCancelAndPay() throws InterruptedException, ExecutionException, TimeoutException { - triggerUIAndWait(getReadyForInput()); + mPaymentRequestTestRule.triggerUIAndWait(mPaymentRequestTestRule.getReadyForInput()); // Check that there is a selected payment method (makes sure we are not ready to pay because // of the Shipping Address). - expectPaymentMethodRowIsSelected(0); - clickInShippingAddressAndWait(R.id.payments_section, getReadyForInput()); - clickInShippingAddressAndWait(R.id.payments_first_radio_button, getReadyToPay()); - expectShippingAddressRowIsSelected(0); - clickInShippingAddressAndWait(R.id.payments_open_editor_pencil_button, getReadyToEdit()); - setTextInEditorAndWait(new String[] {"Jane Doe"}, getEditorTextUpdate()); + mPaymentRequestTestRule.expectPaymentMethodRowIsSelected(0); + mPaymentRequestTestRule.clickInShippingAddressAndWait( + R.id.payments_section, mPaymentRequestTestRule.getReadyForInput()); + mPaymentRequestTestRule.clickInShippingAddressAndWait( + R.id.payments_first_radio_button, mPaymentRequestTestRule.getReadyToPay()); + mPaymentRequestTestRule.expectShippingAddressRowIsSelected(0); + mPaymentRequestTestRule.clickInShippingAddressAndWait( + R.id.payments_open_editor_pencil_button, mPaymentRequestTestRule.getReadyToEdit()); + mPaymentRequestTestRule.setTextInEditorAndWait( + new String[] {"Jane Doe"}, mPaymentRequestTestRule.getEditorTextUpdate()); // Cancel the edit. - clickInEditorAndWait(R.id.payments_edit_cancel_button, getReadyToPay()); - expectShippingAddressRowIsSelected(0); + mPaymentRequestTestRule.clickInEditorAndWait( + R.id.payments_edit_cancel_button, mPaymentRequestTestRule.getReadyToPay()); + mPaymentRequestTestRule.expectShippingAddressRowIsSelected(0); - clickAndWait(R.id.button_primary, getReadyForUnmaskInput()); - setTextInCardUnmaskDialogAndWait(R.id.card_unmask_input, "123", getReadyToUnmask()); - clickCardUnmaskButtonAndWait(DialogInterface.BUTTON_POSITIVE, getDismissed()); - expectResultContains(new String[] {"Jon Doe", "4111111111111111", "12", "2050", "visa", - "123", "Google", "340 Main St", "CA", "Los Angeles", "90291", "+16502530000", "US", - "en", "californiaShippingOption"}); + mPaymentRequestTestRule.clickAndWait( + R.id.button_primary, mPaymentRequestTestRule.getReadyForUnmaskInput()); + mPaymentRequestTestRule.setTextInCardUnmaskDialogAndWait( + R.id.card_unmask_input, "123", mPaymentRequestTestRule.getReadyToUnmask()); + mPaymentRequestTestRule.clickCardUnmaskButtonAndWait( + DialogInterface.BUTTON_POSITIVE, mPaymentRequestTestRule.getDismissed()); + mPaymentRequestTestRule.expectResultContains(new String[] {"Jon Doe", "4111111111111111", + "12", "2050", "visa", "123", "Google", "340 Main St", "CA", "Los Angeles", "90291", + "+16502530000", "US", "en", "californiaShippingOption"}); } /** Attempt to add an invalid address and cancel the transaction. */ + @Test @MediumTest @Feature({"Payments"}) public void testAddInvalidAddressAndCancel() throws InterruptedException, ExecutionException, TimeoutException { - triggerUIAndWait(getReadyForInput()); + mPaymentRequestTestRule.triggerUIAndWait(mPaymentRequestTestRule.getReadyForInput()); // Check that there is a selected payment method (makes sure we are not ready to pay because // of the Shipping Address). - expectPaymentMethodRowIsSelected(0); - clickInShippingSummaryAndWait(R.id.payments_section, getReadyForInput()); - clickInShippingAddressAndWait(R.id.payments_add_option_button, getReadyToEdit()); - clickInEditorAndWait(R.id.payments_edit_done_button, getEditorValidationError()); - clickInEditorAndWait(R.id.payments_edit_cancel_button, getReadyForInput()); + mPaymentRequestTestRule.expectPaymentMethodRowIsSelected(0); + mPaymentRequestTestRule.clickInShippingSummaryAndWait( + R.id.payments_section, mPaymentRequestTestRule.getReadyForInput()); + mPaymentRequestTestRule.clickInShippingAddressAndWait( + R.id.payments_add_option_button, mPaymentRequestTestRule.getReadyToEdit()); + mPaymentRequestTestRule.clickInEditorAndWait( + R.id.payments_edit_done_button, mPaymentRequestTestRule.getEditorValidationError()); + mPaymentRequestTestRule.clickInEditorAndWait( + R.id.payments_edit_cancel_button, mPaymentRequestTestRule.getReadyForInput()); - clickAndWait(R.id.close_button, getDismissed()); - expectResultContains(new String[] {"Request cancelled"}); + mPaymentRequestTestRule.clickAndWait( + R.id.close_button, mPaymentRequestTestRule.getDismissed()); + mPaymentRequestTestRule.expectResultContains(new String[] {"Request cancelled"}); } /** @@ -144,137 +190,157 @@ * @MediumTest * @Restriction(RESTRICTION_TYPE_NON_LOW_END_DEVICE) // crbug.com/626289 */ + @Test @FlakyTest(message = "crbug.com/626289") @Feature({"Payments"}) public void testAddAddressAndPay() throws InterruptedException, ExecutionException, TimeoutException { - triggerUIAndWait(getReadyForInput()); - clickInShippingSummaryAndWait(R.id.payments_section, getReadyForInput()); - clickInShippingAddressAndWait(R.id.payments_add_option_button, getReadyToEdit()); - setTextInEditorAndWait(new String[] {"Bob", "Google", "1600 Amphitheatre Pkwy", - "Mountain View", "CA", "94043", "650-253-0000"}, - getEditorTextUpdate()); - clickInEditorAndWait(R.id.payments_edit_done_button, getReadyToPay()); - clickAndWait(R.id.button_primary, getReadyForUnmaskInput()); - setTextInCardUnmaskDialogAndWait(R.id.card_unmask_input, "123", getReadyToUnmask()); - clickCardUnmaskButtonAndWait(DialogInterface.BUTTON_POSITIVE, getDismissed()); - expectResultContains(new String[] {"Bob", "Google", "1600 Amphitheatre Pkwy", - "Mountain View", "CA", "94043", "+16502530000"}); + mPaymentRequestTestRule.triggerUIAndWait(mPaymentRequestTestRule.getReadyForInput()); + mPaymentRequestTestRule.clickInShippingSummaryAndWait( + R.id.payments_section, mPaymentRequestTestRule.getReadyForInput()); + mPaymentRequestTestRule.clickInShippingAddressAndWait( + R.id.payments_add_option_button, mPaymentRequestTestRule.getReadyToEdit()); + mPaymentRequestTestRule.setTextInEditorAndWait( + new String[] {"Bob", "Google", "1600 Amphitheatre Pkwy", "Mountain View", "CA", + "94043", "650-253-0000"}, + mPaymentRequestTestRule.getEditorTextUpdate()); + mPaymentRequestTestRule.clickInEditorAndWait( + R.id.payments_edit_done_button, mPaymentRequestTestRule.getReadyToPay()); + mPaymentRequestTestRule.clickAndWait( + R.id.button_primary, mPaymentRequestTestRule.getReadyForUnmaskInput()); + mPaymentRequestTestRule.setTextInCardUnmaskDialogAndWait( + R.id.card_unmask_input, "123", mPaymentRequestTestRule.getReadyToUnmask()); + mPaymentRequestTestRule.clickCardUnmaskButtonAndWait( + DialogInterface.BUTTON_POSITIVE, mPaymentRequestTestRule.getDismissed()); + mPaymentRequestTestRule.expectResultContains(new String[] {"Bob", "Google", + "1600 Amphitheatre Pkwy", "Mountain View", "CA", "94043", "+16502530000"}); } /** Quickly pressing "add address" and then [X] should not crash. */ + @Test @MediumTest @Feature({"Payments"}) public void testQuickAddAddressAndCloseShouldNotCrash() throws InterruptedException, ExecutionException, TimeoutException { - triggerUIAndWait(getReadyForInput()); - clickInShippingSummaryAndWait(R.id.payments_section, getReadyForInput()); + mPaymentRequestTestRule.triggerUIAndWait(mPaymentRequestTestRule.getReadyForInput()); + mPaymentRequestTestRule.clickInShippingSummaryAndWait( + R.id.payments_section, mPaymentRequestTestRule.getReadyForInput()); // Quickly press "add address" and then [X]. - int callCount = getReadyToEdit().getCallCount(); + int callCount = mPaymentRequestTestRule.getReadyToEdit().getCallCount(); ThreadUtils.runOnUiThreadBlocking(new Runnable() { @Override public void run() { - getPaymentRequestUI() + mPaymentRequestTestRule.getPaymentRequestUI() .getShippingAddressSectionForTest() .findViewById(R.id.payments_add_option_button) .performClick(); - getPaymentRequestUI() + mPaymentRequestTestRule.getPaymentRequestUI() .getDialogForTest() .findViewById(R.id.close_button) .performClick(); } }); - getReadyToEdit().waitForCallback(callCount); + mPaymentRequestTestRule.getReadyToEdit().waitForCallback(callCount); - clickInEditorAndWait(R.id.payments_edit_cancel_button, getReadyForInput()); - clickAndWait(R.id.close_button, getDismissed()); - expectResultContains(new String[] {"Request cancelled"}); + mPaymentRequestTestRule.clickInEditorAndWait( + R.id.payments_edit_cancel_button, mPaymentRequestTestRule.getReadyForInput()); + mPaymentRequestTestRule.clickAndWait( + R.id.close_button, mPaymentRequestTestRule.getDismissed()); + mPaymentRequestTestRule.expectResultContains(new String[] {"Request cancelled"}); } /** Quickly pressing [X] and then "add address" should not crash. */ + @Test @MediumTest @Feature({"Payments"}) public void testQuickCloseAndAddAddressShouldNotCrash() throws InterruptedException, ExecutionException, TimeoutException { - triggerUIAndWait(getReadyForInput()); - clickInShippingSummaryAndWait(R.id.payments_section, getReadyForInput()); + mPaymentRequestTestRule.triggerUIAndWait(mPaymentRequestTestRule.getReadyForInput()); + mPaymentRequestTestRule.clickInShippingSummaryAndWait( + R.id.payments_section, mPaymentRequestTestRule.getReadyForInput()); // Quickly press [X] and then "add address." - int callCount = getDismissed().getCallCount(); + int callCount = mPaymentRequestTestRule.getDismissed().getCallCount(); ThreadUtils.runOnUiThreadBlocking(new Runnable() { @Override public void run() { - getPaymentRequestUI() + mPaymentRequestTestRule.getPaymentRequestUI() .getDialogForTest() .findViewById(R.id.close_button) .performClick(); - getPaymentRequestUI() + mPaymentRequestTestRule.getPaymentRequestUI() .getShippingAddressSectionForTest() .findViewById(R.id.payments_add_option_button) .performClick(); } }); - getDismissed().waitForCallback(callCount); + mPaymentRequestTestRule.getDismissed().waitForCallback(callCount); - expectResultContains(new String[] {"Request cancelled"}); + mPaymentRequestTestRule.expectResultContains(new String[] {"Request cancelled"}); } /** Quickly pressing "add address" and then "cancel" should not crash. */ + @Test @MediumTest @Feature({"Payments"}) public void testQuickAddAddressAndCancelShouldNotCrash() throws InterruptedException, ExecutionException, TimeoutException { - triggerUIAndWait(getReadyForInput()); - clickInShippingSummaryAndWait(R.id.payments_section, getReadyForInput()); + mPaymentRequestTestRule.triggerUIAndWait(mPaymentRequestTestRule.getReadyForInput()); + mPaymentRequestTestRule.clickInShippingSummaryAndWait( + R.id.payments_section, mPaymentRequestTestRule.getReadyForInput()); // Quickly press "add address" and then "cancel." - int callCount = getReadyToEdit().getCallCount(); + int callCount = mPaymentRequestTestRule.getReadyToEdit().getCallCount(); ThreadUtils.runOnUiThreadBlocking(new Runnable() { @Override public void run() { - getPaymentRequestUI() + mPaymentRequestTestRule.getPaymentRequestUI() .getShippingAddressSectionForTest() .findViewById(R.id.payments_add_option_button) .performClick(); - getPaymentRequestUI() + mPaymentRequestTestRule.getPaymentRequestUI() .getDialogForTest() .findViewById(R.id.button_secondary) .performClick(); } }); - getReadyToEdit().waitForCallback(callCount); + mPaymentRequestTestRule.getReadyToEdit().waitForCallback(callCount); - clickInEditorAndWait(R.id.payments_edit_cancel_button, getReadyForInput()); - clickAndWait(R.id.close_button, getDismissed()); - expectResultContains(new String[] {"Request cancelled"}); + mPaymentRequestTestRule.clickInEditorAndWait( + R.id.payments_edit_cancel_button, mPaymentRequestTestRule.getReadyForInput()); + mPaymentRequestTestRule.clickAndWait( + R.id.close_button, mPaymentRequestTestRule.getDismissed()); + mPaymentRequestTestRule.expectResultContains(new String[] {"Request cancelled"}); } /** Quickly pressing on "cancel" and then "add address" should not crash. */ + @Test @MediumTest @Feature({"Payments"}) public void testQuickCancelAndAddAddressShouldNotCrash() throws InterruptedException, ExecutionException, TimeoutException { - triggerUIAndWait(getReadyForInput()); - clickInShippingSummaryAndWait(R.id.payments_section, getReadyForInput()); + mPaymentRequestTestRule.triggerUIAndWait(mPaymentRequestTestRule.getReadyForInput()); + mPaymentRequestTestRule.clickInShippingSummaryAndWait( + R.id.payments_section, mPaymentRequestTestRule.getReadyForInput()); // Quickly press on "cancel" and then "add address." - int callCount = getDismissed().getCallCount(); + int callCount = mPaymentRequestTestRule.getDismissed().getCallCount(); ThreadUtils.runOnUiThreadBlocking(new Runnable() { @Override public void run() { - getPaymentRequestUI() + mPaymentRequestTestRule.getPaymentRequestUI() .getDialogForTest() .findViewById(R.id.button_secondary) .performClick(); - getPaymentRequestUI() + mPaymentRequestTestRule.getPaymentRequestUI() .getShippingAddressSectionForTest() .findViewById(R.id.payments_add_option_button) .performClick(); } }); - getDismissed().waitForCallback(callCount); + mPaymentRequestTestRule.getDismissed().waitForCallback(callCount); - expectResultContains(new String[] {"Request cancelled"}); + mPaymentRequestTestRule.expectResultContains(new String[] {"Request cancelled"}); } }
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestEmailAndFreeShippingTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestEmailAndFreeShippingTest.java index a8344960..d53e2fc 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestEmailAndFreeShippingTest.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestEmailAndFreeShippingTest.java
@@ -7,12 +7,22 @@ import android.content.DialogInterface; import android.support.test.filters.MediumTest; +import org.junit.Assert; +import org.junit.Rule; +import org.junit.Test; +import org.junit.runner.RunWith; + import org.chromium.base.metrics.RecordHistogram; +import org.chromium.base.test.util.CommandLineFlags; import org.chromium.base.test.util.Feature; import org.chromium.chrome.R; +import org.chromium.chrome.browser.ChromeSwitches; import org.chromium.chrome.browser.autofill.AutofillTestHelper; import org.chromium.chrome.browser.autofill.PersonalDataManager.AutofillProfile; import org.chromium.chrome.browser.autofill.PersonalDataManager.CreditCard; +import org.chromium.chrome.browser.payments.PaymentRequestTestRule.MainActivityStartCallback; +import org.chromium.chrome.test.ChromeActivityTestRule; +import org.chromium.chrome.test.ChromeJUnit4ClassRunner; import java.util.concurrent.ExecutionException; import java.util.concurrent.TimeoutException; @@ -21,11 +31,15 @@ * A payment integration test for a merchant that requires and email address and provides free * shipping regardless of address. */ -public class PaymentRequestEmailAndFreeShippingTest extends PaymentRequestTestBase { - public PaymentRequestEmailAndFreeShippingTest() { - // This merchant requests and email address and provides free shipping worldwide. - super("payment_request_email_and_free_shipping_test.html"); - } +@RunWith(ChromeJUnit4ClassRunner.class) +@CommandLineFlags.Add({ + ChromeSwitches.DISABLE_FIRST_RUN_EXPERIENCE, + ChromeActivityTestRule.DISABLE_NETWORK_PREDICTION_FLAG, +}) +public class PaymentRequestEmailAndFreeShippingTest implements MainActivityStartCallback { + @Rule + public PaymentRequestTestRule mPaymentRequestTestRule = + new PaymentRequestTestRule("payment_request_email_and_free_shipping_test.html", this); @Override public void onMainActivityStarted() @@ -41,16 +55,20 @@ } /** Submit the email and the shipping address to the merchant when the user clicks "Pay." */ + @Test @MediumTest @Feature({"Payments"}) public void testPay() throws InterruptedException, ExecutionException, TimeoutException { - triggerUIAndWait(getReadyToPay()); - clickAndWait(R.id.button_primary, getReadyForUnmaskInput()); - setTextInCardUnmaskDialogAndWait(R.id.card_unmask_input, "123", getReadyToUnmask()); - clickCardUnmaskButtonAndWait(DialogInterface.BUTTON_POSITIVE, getDismissed()); - expectResultContains(new String[] {"jon.doe@google.com", "Jon Doe", "4111111111111111", - "12", "2050", "visa", "123", "Google", "340 Main St", "CA", "Los Angeles", "90291", - "US", "en", "freeShippingOption"}); + mPaymentRequestTestRule.triggerUIAndWait(mPaymentRequestTestRule.getReadyToPay()); + mPaymentRequestTestRule.clickAndWait( + R.id.button_primary, mPaymentRequestTestRule.getReadyForUnmaskInput()); + mPaymentRequestTestRule.setTextInCardUnmaskDialogAndWait( + R.id.card_unmask_input, "123", mPaymentRequestTestRule.getReadyToUnmask()); + mPaymentRequestTestRule.clickCardUnmaskButtonAndWait( + DialogInterface.BUTTON_POSITIVE, mPaymentRequestTestRule.getDismissed()); + mPaymentRequestTestRule.expectResultContains(new String[] {"jon.doe@google.com", "Jon Doe", + "4111111111111111", "12", "2050", "visa", "123", "Google", "340 Main St", "CA", + "Los Angeles", "90291", "US", "en", "freeShippingOption"}); } /** @@ -58,17 +76,23 @@ * results in the appropriate metric being logged in the PaymentRequest.RequestedInformation * histogram. */ + @Test @MediumTest @Feature({"Payments"}) - public void testRequestedInformationMetric() throws InterruptedException, ExecutionException, - TimeoutException { + public void testRequestedInformationMetric() + throws InterruptedException, ExecutionException, TimeoutException { // Start the Payment Request. - triggerUIAndWait(getReadyToPay()); + mPaymentRequestTestRule.triggerUIAndWait(mPaymentRequestTestRule.getReadyToPay()); // Make sure that only the appropriate enum value was logged. for (int i = 0; i < PaymentRequestMetrics.REQUESTED_INFORMATION_MAX; ++i) { - assertEquals((i == (PaymentRequestMetrics.REQUESTED_INFORMATION_EMAIL - | PaymentRequestMetrics.REQUESTED_INFORMATION_SHIPPING) ? 1 : 0), + Assert.assertEquals( + (i + == (PaymentRequestMetrics.REQUESTED_INFORMATION_EMAIL + | PaymentRequestMetrics + .REQUESTED_INFORMATION_SHIPPING) + ? 1 + : 0), RecordHistogram.getHistogramValueCountForTesting( "PaymentRequest.RequestedInformation", i)); }
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestEmailAndPhoneTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestEmailAndPhoneTest.java index b6c0d52f..b8dc730 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestEmailAndPhoneTest.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestEmailAndPhoneTest.java
@@ -4,13 +4,26 @@ package org.chromium.chrome.browser.payments; +import static org.chromium.chrome.browser.payments.PaymentRequestTestRule.HAVE_INSTRUMENTS; +import static org.chromium.chrome.browser.payments.PaymentRequestTestRule.IMMEDIATE_RESPONSE; + import android.support.test.filters.MediumTest; +import org.junit.Assert; +import org.junit.Rule; +import org.junit.Test; +import org.junit.runner.RunWith; + import org.chromium.base.metrics.RecordHistogram; +import org.chromium.base.test.util.CommandLineFlags; import org.chromium.base.test.util.Feature; import org.chromium.chrome.R; +import org.chromium.chrome.browser.ChromeSwitches; import org.chromium.chrome.browser.autofill.AutofillTestHelper; import org.chromium.chrome.browser.autofill.PersonalDataManager.AutofillProfile; +import org.chromium.chrome.browser.payments.PaymentRequestTestRule.MainActivityStartCallback; +import org.chromium.chrome.test.ChromeActivityTestRule; +import org.chromium.chrome.test.ChromeJUnit4ClassRunner; import java.util.concurrent.ExecutionException; import java.util.concurrent.TimeoutException; @@ -18,11 +31,15 @@ /** * A payment integration test for a merchant that requests email address and a phone number. */ -public class PaymentRequestEmailAndPhoneTest extends PaymentRequestTestBase { - public PaymentRequestEmailAndPhoneTest() { - // This merchant request an email address and a phone number. - super("payment_request_email_and_phone_test.html"); - } +@RunWith(ChromeJUnit4ClassRunner.class) +@CommandLineFlags.Add({ + ChromeSwitches.DISABLE_FIRST_RUN_EXPERIENCE, + ChromeActivityTestRule.DISABLE_NETWORK_PREDICTION_FLAG, +}) +public class PaymentRequestEmailAndPhoneTest implements MainActivityStartCallback { + @Rule + public PaymentRequestTestRule mPaymentRequestTestRule = + new PaymentRequestTestRule("payment_request_email_and_phone_test.html", this); @Override public void onMainActivityStarted() @@ -53,78 +70,98 @@ "Google", "340 Main St", "CA", "Los Angeles", "", "90291", "", "US", "555-555-5555", "jon.doe@google.com", "en-US")); - installPaymentApp(HAVE_INSTRUMENTS, IMMEDIATE_RESPONSE); + mPaymentRequestTestRule.installPaymentApp(HAVE_INSTRUMENTS, IMMEDIATE_RESPONSE); } /** Provide the existing valid email address and phone number to the merchant. */ + @Test @MediumTest @Feature({"Payments"}) public void testPay() throws InterruptedException, ExecutionException, TimeoutException { - triggerUIAndWait(getReadyToPay()); - clickAndWait(R.id.button_primary, getDismissed()); - expectResultContains(new String[] {"+15555555555", "jon.doe@google.com"}); + mPaymentRequestTestRule.triggerUIAndWait(mPaymentRequestTestRule.getReadyToPay()); + mPaymentRequestTestRule.clickAndWait( + R.id.button_primary, mPaymentRequestTestRule.getDismissed()); + mPaymentRequestTestRule.expectResultContains( + new String[] {"+15555555555", "jon.doe@google.com"}); } /** Attempt to add an invalid email address and phone number and cancel the transaction. */ + @Test @MediumTest @Feature({"Payments"}) public void testAddInvalidEmailAndCancel() throws InterruptedException, ExecutionException, TimeoutException { - triggerUIAndWait(getReadyToPay()); - clickInContactInfoAndWait(R.id.payments_section, getReadyForInput()); - clickInContactInfoAndWait(R.id.payments_add_option_button, getReadyToEdit()); - setTextInEditorAndWait(new String[] {"-1-", "jane.jones"}, getEditorTextUpdate()); - clickInEditorAndWait(R.id.payments_edit_done_button, getEditorValidationError()); - clickInEditorAndWait(R.id.payments_edit_cancel_button, getReadyToPay()); - clickAndWait(R.id.close_button, getDismissed()); - expectResultContains(new String[] {"Request cancelled"}); + mPaymentRequestTestRule.triggerUIAndWait(mPaymentRequestTestRule.getReadyToPay()); + mPaymentRequestTestRule.clickInContactInfoAndWait( + R.id.payments_section, mPaymentRequestTestRule.getReadyForInput()); + mPaymentRequestTestRule.clickInContactInfoAndWait( + R.id.payments_add_option_button, mPaymentRequestTestRule.getReadyToEdit()); + mPaymentRequestTestRule.setTextInEditorAndWait( + new String[] {"-1-", "jane.jones"}, mPaymentRequestTestRule.getEditorTextUpdate()); + mPaymentRequestTestRule.clickInEditorAndWait( + R.id.payments_edit_done_button, mPaymentRequestTestRule.getEditorValidationError()); + mPaymentRequestTestRule.clickInEditorAndWait( + R.id.payments_edit_cancel_button, mPaymentRequestTestRule.getReadyToPay()); + mPaymentRequestTestRule.clickAndWait( + R.id.close_button, mPaymentRequestTestRule.getDismissed()); + mPaymentRequestTestRule.expectResultContains(new String[] {"Request cancelled"}); } /** Add a new email address and phone number and provide that to the merchant. */ + @Test @MediumTest @Feature({"Payments"}) public void testAddEmailAndPhoneAndPay() throws InterruptedException, ExecutionException, TimeoutException { - triggerUIAndWait(getReadyToPay()); - clickInContactInfoAndWait(R.id.payments_section, getReadyForInput()); - clickInContactInfoAndWait(R.id.payments_add_option_button, getReadyToEdit()); - setTextInEditorAndWait( - new String[] {"555-555-5555", "jane.jones@google.com"}, getEditorTextUpdate()); - clickInEditorAndWait(R.id.payments_edit_done_button, getReadyToPay()); - clickAndWait(R.id.button_primary, getDismissed()); - expectResultContains(new String[] {"+15555555555", "jane.jones@google.com"}); + mPaymentRequestTestRule.triggerUIAndWait(mPaymentRequestTestRule.getReadyToPay()); + mPaymentRequestTestRule.clickInContactInfoAndWait( + R.id.payments_section, mPaymentRequestTestRule.getReadyForInput()); + mPaymentRequestTestRule.clickInContactInfoAndWait( + R.id.payments_add_option_button, mPaymentRequestTestRule.getReadyToEdit()); + mPaymentRequestTestRule.setTextInEditorAndWait( + new String[] {"555-555-5555", "jane.jones@google.com"}, + mPaymentRequestTestRule.getEditorTextUpdate()); + mPaymentRequestTestRule.clickInEditorAndWait( + R.id.payments_edit_done_button, mPaymentRequestTestRule.getReadyToPay()); + mPaymentRequestTestRule.clickAndWait( + R.id.button_primary, mPaymentRequestTestRule.getDismissed()); + mPaymentRequestTestRule.expectResultContains( + new String[] {"+15555555555", "jane.jones@google.com"}); } /** * Makes sure that suggestions that are equal to or subsets of other suggestions are not shown * to the user. */ + @Test @MediumTest @Feature({"Payments"}) public void testSuggestionsDeduped() throws InterruptedException, ExecutionException, TimeoutException { - triggerUIAndWait(getReadyToPay()); - clickInContactInfoAndWait(R.id.payments_section, getReadyForInput()); - assertEquals(1, getNumberOfContactDetailSuggestions()); + mPaymentRequestTestRule.triggerUIAndWait(mPaymentRequestTestRule.getReadyToPay()); + mPaymentRequestTestRule.clickInContactInfoAndWait( + R.id.payments_section, mPaymentRequestTestRule.getReadyForInput()); + Assert.assertEquals(1, mPaymentRequestTestRule.getNumberOfContactDetailSuggestions()); } /** * Test that starting a payment request that requires only the user's email address results in * the appropriate metric being logged in the PaymentRequest.RequestedInformation histogram. */ + @Test @MediumTest @Feature({"Payments"}) public void testRequestedInformationMetric() throws InterruptedException, ExecutionException, TimeoutException { // Start the Payment Request. - triggerUIAndWait(getReadyToPay()); + mPaymentRequestTestRule.triggerUIAndWait(mPaymentRequestTestRule.getReadyToPay()); int appropriateEnumValue = PaymentRequestMetrics.REQUESTED_INFORMATION_EMAIL | PaymentRequestMetrics.REQUESTED_INFORMATION_PHONE; // Make sure that only the appropriate enum value was logged. for (int i = 0; i < PaymentRequestMetrics.REQUESTED_INFORMATION_MAX; ++i) { - assertEquals((i == (appropriateEnumValue) ? 1 : 0), + Assert.assertEquals((i == (appropriateEnumValue) ? 1 : 0), RecordHistogram.getHistogramValueCountForTesting( "PaymentRequest.RequestedInformation", i)); }
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestEmailTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestEmailTest.java index afa3fab..a911019c 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestEmailTest.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestEmailTest.java
@@ -4,13 +4,26 @@ package org.chromium.chrome.browser.payments; +import static org.chromium.chrome.browser.payments.PaymentRequestTestRule.HAVE_INSTRUMENTS; +import static org.chromium.chrome.browser.payments.PaymentRequestTestRule.IMMEDIATE_RESPONSE; + import android.support.test.filters.MediumTest; +import org.junit.Assert; +import org.junit.Rule; +import org.junit.Test; +import org.junit.runner.RunWith; + import org.chromium.base.metrics.RecordHistogram; +import org.chromium.base.test.util.CommandLineFlags; import org.chromium.base.test.util.Feature; import org.chromium.chrome.R; +import org.chromium.chrome.browser.ChromeSwitches; import org.chromium.chrome.browser.autofill.AutofillTestHelper; import org.chromium.chrome.browser.autofill.PersonalDataManager.AutofillProfile; +import org.chromium.chrome.browser.payments.PaymentRequestTestRule.MainActivityStartCallback; +import org.chromium.chrome.test.ChromeActivityTestRule; +import org.chromium.chrome.test.ChromeJUnit4ClassRunner; import java.util.concurrent.ExecutionException; import java.util.concurrent.TimeoutException; @@ -18,11 +31,15 @@ /** * A payment integration test for a merchant that requests email address. */ -public class PaymentRequestEmailTest extends PaymentRequestTestBase { - public PaymentRequestEmailTest() { - // This merchant request an email address. - super("payment_request_email_test.html"); - } +@RunWith(ChromeJUnit4ClassRunner.class) +@CommandLineFlags.Add({ + ChromeSwitches.DISABLE_FIRST_RUN_EXPERIENCE, + ChromeActivityTestRule.DISABLE_NETWORK_PREDICTION_FLAG, +}) +public class PaymentRequestEmailTest implements MainActivityStartCallback { + @Rule + public PaymentRequestTestRule mPaymentRequestTestRule = + new PaymentRequestTestRule("payment_request_email_test.html", this); @Override public void onMainActivityStarted() @@ -53,75 +70,93 @@ "Google", "340 Main St", "CA", "Los Angeles", "", "90291", "", "US", "555-555-5555", "jon.doe@google.com", "en-US")); - installPaymentApp(HAVE_INSTRUMENTS, IMMEDIATE_RESPONSE); + mPaymentRequestTestRule.installPaymentApp(HAVE_INSTRUMENTS, IMMEDIATE_RESPONSE); } /** Provide the existing valid email address to the merchant. */ + @Test @MediumTest @Feature({"Payments"}) public void testPay() throws InterruptedException, ExecutionException, TimeoutException { - triggerUIAndWait(getReadyToPay()); - clickAndWait(R.id.button_primary, getDismissed()); - expectResultContains(new String[] {"jon.doe@google.com"}); + mPaymentRequestTestRule.triggerUIAndWait(mPaymentRequestTestRule.getReadyToPay()); + mPaymentRequestTestRule.clickAndWait( + R.id.button_primary, mPaymentRequestTestRule.getDismissed()); + mPaymentRequestTestRule.expectResultContains(new String[] {"jon.doe@google.com"}); } /** Attempt to add an invalid email address and cancel the transaction. */ + @Test @MediumTest @Feature({"Payments"}) public void testAddInvalidEmailAndCancel() throws InterruptedException, ExecutionException, TimeoutException { - triggerUIAndWait(getReadyToPay()); - clickInContactInfoAndWait(R.id.payments_section, getReadyForInput()); - clickInContactInfoAndWait(R.id.payments_add_option_button, getReadyToEdit()); - setTextInEditorAndWait(new String[] {"jane.jones"}, getEditorTextUpdate()); - clickInEditorAndWait(R.id.payments_edit_done_button, getEditorValidationError()); - clickInEditorAndWait(R.id.payments_edit_cancel_button, getReadyToPay()); - clickAndWait(R.id.close_button, getDismissed()); - expectResultContains(new String[] {"Request cancelled"}); + mPaymentRequestTestRule.triggerUIAndWait(mPaymentRequestTestRule.getReadyToPay()); + mPaymentRequestTestRule.clickInContactInfoAndWait( + R.id.payments_section, mPaymentRequestTestRule.getReadyForInput()); + mPaymentRequestTestRule.clickInContactInfoAndWait( + R.id.payments_add_option_button, mPaymentRequestTestRule.getReadyToEdit()); + mPaymentRequestTestRule.setTextInEditorAndWait( + new String[] {"jane.jones"}, mPaymentRequestTestRule.getEditorTextUpdate()); + mPaymentRequestTestRule.clickInEditorAndWait( + R.id.payments_edit_done_button, mPaymentRequestTestRule.getEditorValidationError()); + mPaymentRequestTestRule.clickInEditorAndWait( + R.id.payments_edit_cancel_button, mPaymentRequestTestRule.getReadyToPay()); + mPaymentRequestTestRule.clickAndWait( + R.id.close_button, mPaymentRequestTestRule.getDismissed()); + mPaymentRequestTestRule.expectResultContains(new String[] {"Request cancelled"}); } /** Add a new email address and provide that to the merchant. */ + @Test @MediumTest @Feature({"Payments"}) public void testAddEmailAndPay() throws InterruptedException, ExecutionException, TimeoutException { - triggerUIAndWait(getReadyToPay()); - clickInContactInfoAndWait(R.id.payments_section, getReadyForInput()); - clickInContactInfoAndWait(R.id.payments_add_option_button, getReadyToEdit()); - setTextInEditorAndWait(new String[] {"jane.jones@google.com"}, getEditorTextUpdate()); - clickInEditorAndWait(R.id.payments_edit_done_button, getReadyToPay()); + mPaymentRequestTestRule.triggerUIAndWait(mPaymentRequestTestRule.getReadyToPay()); + mPaymentRequestTestRule.clickInContactInfoAndWait( + R.id.payments_section, mPaymentRequestTestRule.getReadyForInput()); + mPaymentRequestTestRule.clickInContactInfoAndWait( + R.id.payments_add_option_button, mPaymentRequestTestRule.getReadyToEdit()); + mPaymentRequestTestRule.setTextInEditorAndWait(new String[] {"jane.jones@google.com"}, + mPaymentRequestTestRule.getEditorTextUpdate()); + mPaymentRequestTestRule.clickInEditorAndWait( + R.id.payments_edit_done_button, mPaymentRequestTestRule.getReadyToPay()); - clickAndWait(R.id.button_primary, getDismissed()); - expectResultContains(new String[] {"jane.jones@google.com"}); + mPaymentRequestTestRule.clickAndWait( + R.id.button_primary, mPaymentRequestTestRule.getDismissed()); + mPaymentRequestTestRule.expectResultContains(new String[] {"jane.jones@google.com"}); } /** * Makes sure that suggestions that are equal to or subsets of other suggestions are not shown * to the user. */ + @Test @MediumTest @Feature({"Payments"}) public void testSuggestionsDeduped() throws InterruptedException, ExecutionException, TimeoutException { - triggerUIAndWait(getReadyToPay()); - clickInContactInfoAndWait(R.id.payments_section, getReadyForInput()); - assertEquals(1, getNumberOfContactDetailSuggestions()); + mPaymentRequestTestRule.triggerUIAndWait(mPaymentRequestTestRule.getReadyToPay()); + mPaymentRequestTestRule.clickInContactInfoAndWait( + R.id.payments_section, mPaymentRequestTestRule.getReadyForInput()); + Assert.assertEquals(1, mPaymentRequestTestRule.getNumberOfContactDetailSuggestions()); } /** * Test that starting a payment request that requires only the user's email address results in * the appropriate metric being logged in the PaymentRequest.RequestedInformation histogram. */ + @Test @MediumTest @Feature({"Payments"}) - public void testRequestedInformationMetric() throws InterruptedException, ExecutionException, - TimeoutException { + public void testRequestedInformationMetric() + throws InterruptedException, ExecutionException, TimeoutException { // Start the Payment Request. - triggerUIAndWait(getReadyToPay()); + mPaymentRequestTestRule.triggerUIAndWait(mPaymentRequestTestRule.getReadyToPay()); // Make sure that only the appropriate enum value was logged. for (int i = 0; i < PaymentRequestMetrics.REQUESTED_INFORMATION_MAX; ++i) { - assertEquals((i == PaymentRequestMetrics.REQUESTED_INFORMATION_EMAIL ? 1 : 0), + Assert.assertEquals((i == PaymentRequestMetrics.REQUESTED_INFORMATION_EMAIL ? 1 : 0), RecordHistogram.getHistogramValueCountForTesting( "PaymentRequest.RequestedInformation", i)); }
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestExpiredLocalCardTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestExpiredLocalCardTest.java index 79e5154..1877d7f 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestExpiredLocalCardTest.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestExpiredLocalCardTest.java
@@ -7,12 +7,22 @@ import android.content.DialogInterface; import android.support.test.filters.MediumTest; +import org.junit.Assert; +import org.junit.Rule; +import org.junit.Test; +import org.junit.runner.RunWith; + +import org.chromium.base.test.util.CommandLineFlags; import org.chromium.base.test.util.DisabledTest; import org.chromium.base.test.util.Feature; import org.chromium.chrome.R; +import org.chromium.chrome.browser.ChromeSwitches; import org.chromium.chrome.browser.autofill.AutofillTestHelper; import org.chromium.chrome.browser.autofill.PersonalDataManager.AutofillProfile; import org.chromium.chrome.browser.autofill.PersonalDataManager.CreditCard; +import org.chromium.chrome.browser.payments.PaymentRequestTestRule.MainActivityStartCallback; +import org.chromium.chrome.test.ChromeActivityTestRule; +import org.chromium.chrome.test.ChromeJUnit4ClassRunner; import java.util.Calendar; import java.util.concurrent.ExecutionException; @@ -21,10 +31,15 @@ /** * A payment integration test for a user that pays with an expired local credit card. */ -public class PaymentRequestExpiredLocalCardTest extends PaymentRequestTestBase { - public PaymentRequestExpiredLocalCardTest() { - super("payment_request_free_shipping_test.html"); - } +@RunWith(ChromeJUnit4ClassRunner.class) +@CommandLineFlags.Add({ + ChromeSwitches.DISABLE_FIRST_RUN_EXPERIENCE, + ChromeActivityTestRule.DISABLE_NETWORK_PREDICTION_FLAG, +}) +public class PaymentRequestExpiredLocalCardTest implements MainActivityStartCallback { + @Rule + public PaymentRequestTestRule mPaymentRequestTestRule = + new PaymentRequestTestRule("payment_request_free_shipping_test.html", this); AutofillTestHelper mHelper; String mCreditCardId; @@ -48,45 +63,52 @@ * credit card is expired. Also tests that the user can pay once they have entered a new valid * expiration date and that merchant receives the updated data. */ + @Test @MediumTest @Feature({"Payments"}) public void testPayWithExpiredCard_ValidExpiration() throws InterruptedException, ExecutionException, TimeoutException { - triggerUIAndWait(getReadyToPay()); - clickAndWait(R.id.button_primary, getReadyForUnmaskInput()); - setTextInExpiredCardUnmaskDialogAndWait( + mPaymentRequestTestRule.triggerUIAndWait(mPaymentRequestTestRule.getReadyToPay()); + mPaymentRequestTestRule.clickAndWait( + R.id.button_primary, mPaymentRequestTestRule.getReadyForUnmaskInput()); + mPaymentRequestTestRule.setTextInExpiredCardUnmaskDialogAndWait( new int[] {R.id.expiration_month, R.id.expiration_year, R.id.card_unmask_input}, - new String[] {"11", "26", "123"}, getReadyToUnmask()); - clickCardUnmaskButtonAndWait(DialogInterface.BUTTON_POSITIVE, getDismissed()); - expectResultContains(new String[] {"Jon Doe", "4111111111111111", "11", "2026", "visa", - "123", "Google", "340 Main St", "CA", "Los Angeles", "90291", "US", "en", - "freeShippingOption"}); + new String[] {"11", "26", "123"}, mPaymentRequestTestRule.getReadyToUnmask()); + mPaymentRequestTestRule.clickCardUnmaskButtonAndWait( + DialogInterface.BUTTON_POSITIVE, mPaymentRequestTestRule.getDismissed()); + mPaymentRequestTestRule.expectResultContains(new String[] {"Jon Doe", "4111111111111111", + "11", "2026", "visa", "123", "Google", "340 Main St", "CA", "Los Angeles", "90291", + "US", "en", "freeShippingOption"}); } /** * Tests that the new expiration date entered in the unmasking prompt for an expired card * overwrites that card's old expiration date. */ + @Test @MediumTest @Feature({"Payments"}) public void testPayWithExpiredCard_NewExpirationSaved() throws InterruptedException, ExecutionException, TimeoutException { - triggerUIAndWait(getReadyToPay()); - clickAndWait(R.id.button_primary, getReadyForUnmaskInput()); - setTextInExpiredCardUnmaskDialogAndWait( + mPaymentRequestTestRule.triggerUIAndWait(mPaymentRequestTestRule.getReadyToPay()); + mPaymentRequestTestRule.clickAndWait( + R.id.button_primary, mPaymentRequestTestRule.getReadyForUnmaskInput()); + mPaymentRequestTestRule.setTextInExpiredCardUnmaskDialogAndWait( new int[] {R.id.expiration_month, R.id.expiration_year, R.id.card_unmask_input}, - new String[] {"11", "26", "123"}, getReadyToUnmask()); - clickCardUnmaskButtonAndWait(DialogInterface.BUTTON_POSITIVE, getDismissed()); + new String[] {"11", "26", "123"}, mPaymentRequestTestRule.getReadyToUnmask()); + mPaymentRequestTestRule.clickCardUnmaskButtonAndWait( + DialogInterface.BUTTON_POSITIVE, mPaymentRequestTestRule.getDismissed()); // Make sure the new expiration date was saved. CreditCard storedCard = mHelper.getCreditCard(mCreditCardId); - assertEquals("11", storedCard.getMonth()); - assertEquals("2026", storedCard.getYear()); + Assert.assertEquals("11", storedCard.getMonth()); + Assert.assertEquals("2026", storedCard.getYear()); } /** * Tests that it is not possible to add an expired card in a payment request. */ + @Test @MediumTest @Feature({"Payments"}) public void testCannotAddExpiredCard() @@ -96,23 +118,30 @@ Calendar now = Calendar.getInstance(); if (now.get(Calendar.MONTH) == 0) return; - triggerUIAndWait(getReadyToPay()); + mPaymentRequestTestRule.triggerUIAndWait(mPaymentRequestTestRule.getReadyToPay()); // Try to add an expired card. - clickInPaymentMethodAndWait(R.id.payments_section, getReadyForInput()); - clickInPaymentMethodAndWait(R.id.payments_add_option_button, getReadyToEdit()); + mPaymentRequestTestRule.clickInPaymentMethodAndWait( + R.id.payments_section, mPaymentRequestTestRule.getReadyForInput()); + mPaymentRequestTestRule.clickInPaymentMethodAndWait( + R.id.payments_add_option_button, mPaymentRequestTestRule.getReadyToEdit()); // Set the expiration date to past month of the current year. - setSpinnerSelectionsInCardEditorAndWait( - new int[] {now.get(Calendar.MONTH) - 1, 0, 0}, getBillingAddressChangeProcessed()); - setTextInCardEditorAndWait( - new String[] {"4111111111111111", "Jon Doe"}, getEditorTextUpdate()); - clickInCardEditorAndWait(R.id.payments_edit_done_button, getEditorValidationError()); + mPaymentRequestTestRule.setSpinnerSelectionsInCardEditorAndWait( + new int[] {now.get(Calendar.MONTH) - 1, 0, 0}, + mPaymentRequestTestRule.getBillingAddressChangeProcessed()); + mPaymentRequestTestRule.setTextInCardEditorAndWait( + new String[] {"4111111111111111", "Jon Doe"}, + mPaymentRequestTestRule.getEditorTextUpdate()); + mPaymentRequestTestRule.clickInCardEditorAndWait( + R.id.payments_edit_done_button, mPaymentRequestTestRule.getEditorValidationError()); // Set the expiration date to the current month of the current year. - setSpinnerSelectionsInCardEditorAndWait( - new int[] {now.get(Calendar.MONTH), 0, 0}, getExpirationMonthChange()); + mPaymentRequestTestRule.setSpinnerSelectionsInCardEditorAndWait( + new int[] {now.get(Calendar.MONTH), 0, 0}, + mPaymentRequestTestRule.getExpirationMonthChange()); - clickInCardEditorAndWait(R.id.payments_edit_done_button, getReadyToPay()); + mPaymentRequestTestRule.clickInCardEditorAndWait( + R.id.payments_edit_done_button, mPaymentRequestTestRule.getReadyToPay()); } /** @@ -121,31 +150,36 @@ // @MediumTest // @Feature({"Payments"}) // See: crbug.com/687438. + @Test @DisabledTest public void testPromptErrorMessages() throws InterruptedException, ExecutionException, TimeoutException { // Click pay to get to the card unmask prompt. - triggerUIAndWait(getReadyToPay()); - clickAndWait(R.id.button_primary, getReadyForUnmaskInput()); + mPaymentRequestTestRule.triggerUIAndWait(mPaymentRequestTestRule.getReadyToPay()); + mPaymentRequestTestRule.clickAndWait( + R.id.button_primary, mPaymentRequestTestRule.getReadyForUnmaskInput()); // Set valid arguments. - setTextInExpiredCardUnmaskDialogAndWait( + mPaymentRequestTestRule.setTextInExpiredCardUnmaskDialogAndWait( new int[] {R.id.expiration_month, R.id.expiration_year, R.id.card_unmask_input}, - new String[] {"10", "26", "123"}, getUnmaskValidationDone()); - assertTrue(getUnmaskPromptErrorMessage().equals("")); + new String[] {"10", "26", "123"}, + mPaymentRequestTestRule.getUnmaskValidationDone()); + Assert.assertTrue(mPaymentRequestTestRule.getUnmaskPromptErrorMessage().equals("")); // Set an invalid expiration month. - setTextInExpiredCardUnmaskDialogAndWait( + mPaymentRequestTestRule.setTextInExpiredCardUnmaskDialogAndWait( new int[] {R.id.expiration_month, R.id.expiration_year, R.id.card_unmask_input}, - new String[] {"99", "25", "123"}, getUnmaskValidationDone()); - assertTrue(getUnmaskPromptErrorMessage().equals( + new String[] {"99", "25", "123"}, + mPaymentRequestTestRule.getUnmaskValidationDone()); + Assert.assertTrue(mPaymentRequestTestRule.getUnmaskPromptErrorMessage().equals( "Check your expiration month and try again")); // Set an invalid expiration year. - setTextInExpiredCardUnmaskDialogAndWait( + mPaymentRequestTestRule.setTextInExpiredCardUnmaskDialogAndWait( new int[] {R.id.expiration_month, R.id.expiration_year, R.id.card_unmask_input}, - new String[] {"10", "14", "123"}, getUnmaskValidationDone()); - assertTrue(getUnmaskPromptErrorMessage().equals( + new String[] {"10", "14", "123"}, + mPaymentRequestTestRule.getUnmaskValidationDone()); + Assert.assertTrue(mPaymentRequestTestRule.getUnmaskPromptErrorMessage().equals( "Check your expiration year and try again")); // If the current date is in January skip this test. It is not possible to select an expired @@ -155,19 +189,20 @@ String twoDigitsYear = Integer.toString(now.get(Calendar.YEAR)).substring(2); // Set an invalid expiration year. - setTextInExpiredCardUnmaskDialogAndWait( + mPaymentRequestTestRule.setTextInExpiredCardUnmaskDialogAndWait( new int[] {R.id.expiration_month, R.id.expiration_year, R.id.card_unmask_input}, new String[] { Integer.toString(now.get(Calendar.MONTH) - 1), twoDigitsYear, "123"}, - getUnmaskValidationDone()); - assertTrue(getUnmaskPromptErrorMessage().equals( + mPaymentRequestTestRule.getUnmaskValidationDone()); + Assert.assertTrue(mPaymentRequestTestRule.getUnmaskPromptErrorMessage().equals( "Check your expiration date and try again")); } // Set valid arguments again. - setTextInExpiredCardUnmaskDialogAndWait( + mPaymentRequestTestRule.setTextInExpiredCardUnmaskDialogAndWait( new int[] {R.id.expiration_month, R.id.expiration_year, R.id.card_unmask_input}, - new String[] {"10", "26", "123"}, getUnmaskValidationDone()); - assertTrue(getUnmaskPromptErrorMessage().equals("")); + new String[] {"10", "26", "123"}, + mPaymentRequestTestRule.getUnmaskValidationDone()); + Assert.assertTrue(mPaymentRequestTestRule.getUnmaskPromptErrorMessage().equals("")); } }
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestExtraShippingOptionsTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestExtraShippingOptionsTest.java index e92bfa7..3ea9de7d 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestExtraShippingOptionsTest.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestExtraShippingOptionsTest.java
@@ -7,11 +7,20 @@ import android.content.DialogInterface; import android.support.test.filters.MediumTest; +import org.junit.Rule; +import org.junit.Test; +import org.junit.runner.RunWith; + +import org.chromium.base.test.util.CommandLineFlags; import org.chromium.base.test.util.Feature; import org.chromium.chrome.R; +import org.chromium.chrome.browser.ChromeSwitches; import org.chromium.chrome.browser.autofill.AutofillTestHelper; import org.chromium.chrome.browser.autofill.PersonalDataManager.AutofillProfile; import org.chromium.chrome.browser.autofill.PersonalDataManager.CreditCard; +import org.chromium.chrome.browser.payments.PaymentRequestTestRule.MainActivityStartCallback; +import org.chromium.chrome.test.ChromeActivityTestRule; +import org.chromium.chrome.test.ChromeJUnit4ClassRunner; import java.util.concurrent.ExecutionException; import java.util.concurrent.TimeoutException; @@ -20,11 +29,15 @@ * A payment integration test for a merchant that provides shipping options, but does not request a * shipping address. */ -public class PaymentRequestExtraShippingOptionsTest extends PaymentRequestTestBase { - public PaymentRequestExtraShippingOptionsTest() { - // This merchant provides shipping options, but does not request a shipping address. - super("payment_request_extra_shipping_options_test.html"); - } +@RunWith(ChromeJUnit4ClassRunner.class) +@CommandLineFlags.Add({ + ChromeSwitches.DISABLE_FIRST_RUN_EXPERIENCE, + ChromeActivityTestRule.DISABLE_NETWORK_PREDICTION_FLAG, +}) +public class PaymentRequestExtraShippingOptionsTest implements MainActivityStartCallback { + @Rule + public PaymentRequestTestRule mPaymentRequestTestRule = + new PaymentRequestTestRule("payment_request_extra_shipping_options_test.html", this); @Override public void onMainActivityStarted() @@ -42,14 +55,19 @@ * Submit the payment information without shipping address or shipping options to the merchant * when the user clicks "Pay." */ + @Test @MediumTest @Feature({"Payments"}) public void testPay() throws InterruptedException, ExecutionException, TimeoutException { - triggerUIAndWait(getReadyToPay()); - clickAndWait(R.id.button_primary, getReadyForUnmaskInput()); - setTextInCardUnmaskDialogAndWait(R.id.card_unmask_input, "123", getReadyToUnmask()); - clickCardUnmaskButtonAndWait(DialogInterface.BUTTON_POSITIVE, getDismissed()); - expectResultContains(new String[] {"Jon Doe", "4111111111111111", "12", "2050", "visa", - "123", "Google", "340 Main St", "CA", "Los Angeles", "90291", "US", "en"}); + mPaymentRequestTestRule.triggerUIAndWait(mPaymentRequestTestRule.getReadyToPay()); + mPaymentRequestTestRule.clickAndWait( + R.id.button_primary, mPaymentRequestTestRule.getReadyForUnmaskInput()); + mPaymentRequestTestRule.setTextInCardUnmaskDialogAndWait( + R.id.card_unmask_input, "123", mPaymentRequestTestRule.getReadyToUnmask()); + mPaymentRequestTestRule.clickCardUnmaskButtonAndWait( + DialogInterface.BUTTON_POSITIVE, mPaymentRequestTestRule.getDismissed()); + mPaymentRequestTestRule.expectResultContains( + new String[] {"Jon Doe", "4111111111111111", "12", "2050", "visa", "123", "Google", + "340 Main St", "CA", "Los Angeles", "90291", "US", "en"}); } }
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestFailCompleteTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestFailCompleteTest.java index b025e68..d879f73 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestFailCompleteTest.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestFailCompleteTest.java
@@ -7,11 +7,20 @@ import android.content.DialogInterface; import android.support.test.filters.MediumTest; +import org.junit.Rule; +import org.junit.Test; +import org.junit.runner.RunWith; + +import org.chromium.base.test.util.CommandLineFlags; import org.chromium.base.test.util.Feature; import org.chromium.chrome.R; +import org.chromium.chrome.browser.ChromeSwitches; import org.chromium.chrome.browser.autofill.AutofillTestHelper; import org.chromium.chrome.browser.autofill.PersonalDataManager.AutofillProfile; import org.chromium.chrome.browser.autofill.PersonalDataManager.CreditCard; +import org.chromium.chrome.browser.payments.PaymentRequestTestRule.MainActivityStartCallback; +import org.chromium.chrome.test.ChromeActivityTestRule; +import org.chromium.chrome.test.ChromeJUnit4ClassRunner; import java.util.concurrent.ExecutionException; import java.util.concurrent.TimeoutException; @@ -19,10 +28,15 @@ /** * A payment integration test for a merchant that always fails to complete the transaction. */ -public class PaymentRequestFailCompleteTest extends PaymentRequestTestBase { - public PaymentRequestFailCompleteTest() { - super("payment_request_fail_complete_test.html"); - } +@RunWith(ChromeJUnit4ClassRunner.class) +@CommandLineFlags.Add({ + ChromeSwitches.DISABLE_FIRST_RUN_EXPERIENCE, + ChromeActivityTestRule.DISABLE_NETWORK_PREDICTION_FLAG, +}) +public class PaymentRequestFailCompleteTest implements MainActivityStartCallback { + @Rule + public PaymentRequestTestRule mPaymentRequestTestRule = + new PaymentRequestTestRule("payment_request_fail_complete_test.html", this); @Override public void onMainActivityStarted() @@ -36,14 +50,19 @@ billingAddressId, "" /* serverId */)); } + @Test @MediumTest @Feature({"Payments"}) public void testPay() throws InterruptedException, ExecutionException, TimeoutException { - triggerUIAndWait(getReadyToPay()); - clickAndWait(R.id.button_primary, getReadyForUnmaskInput()); - setTextInCardUnmaskDialogAndWait(R.id.card_unmask_input, "123", getReadyToUnmask()); - clickCardUnmaskButtonAndWait(DialogInterface.BUTTON_POSITIVE, getResultReady()); - clickAndWait(R.id.ok_button, getDismissed()); - expectResultContains(new String[] {"Transaction failed"}); + mPaymentRequestTestRule.triggerUIAndWait(mPaymentRequestTestRule.getReadyToPay()); + mPaymentRequestTestRule.clickAndWait( + R.id.button_primary, mPaymentRequestTestRule.getReadyForUnmaskInput()); + mPaymentRequestTestRule.setTextInCardUnmaskDialogAndWait( + R.id.card_unmask_input, "123", mPaymentRequestTestRule.getReadyToUnmask()); + mPaymentRequestTestRule.clickCardUnmaskButtonAndWait( + DialogInterface.BUTTON_POSITIVE, mPaymentRequestTestRule.getResultReady()); + mPaymentRequestTestRule.clickAndWait( + R.id.ok_button, mPaymentRequestTestRule.getDismissed()); + mPaymentRequestTestRule.expectResultContains(new String[] {"Transaction failed"}); } }
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestFieldTrialTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestFieldTrialTest.java index 055856c..8fc0de71 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestFieldTrialTest.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestFieldTrialTest.java
@@ -4,12 +4,23 @@ package org.chromium.chrome.browser.payments; +import static org.chromium.chrome.browser.payments.PaymentRequestTestRule.HAVE_INSTRUMENTS; +import static org.chromium.chrome.browser.payments.PaymentRequestTestRule.IMMEDIATE_RESPONSE; + import android.support.test.filters.MediumTest; +import org.junit.Rule; +import org.junit.Test; +import org.junit.runner.RunWith; + import org.chromium.base.test.util.CommandLineFlags; import org.chromium.base.test.util.Feature; +import org.chromium.chrome.browser.ChromeSwitches; import org.chromium.chrome.browser.autofill.AutofillTestHelper; import org.chromium.chrome.browser.autofill.PersonalDataManager.AutofillProfile; +import org.chromium.chrome.browser.payments.PaymentRequestTestRule.MainActivityStartCallback; +import org.chromium.chrome.test.ChromeActivityTestRule; +import org.chromium.chrome.test.ChromeJUnit4ClassRunner; import java.util.concurrent.ExecutionException; import java.util.concurrent.TimeoutException; @@ -17,11 +28,15 @@ /** * A payment integration test for the different fields trials affecting payment requests. */ -public class PaymentRequestFieldTrialTest extends PaymentRequestTestBase { - public PaymentRequestFieldTrialTest() { - // This merchant supports bobpay and credit cards payments. - super("payment_request_bobpay_and_cards_test.html"); - } +@RunWith(ChromeJUnit4ClassRunner.class) +@CommandLineFlags.Add({ + ChromeSwitches.DISABLE_FIRST_RUN_EXPERIENCE, + ChromeActivityTestRule.DISABLE_NETWORK_PREDICTION_FLAG, +}) +public class PaymentRequestFieldTrialTest implements MainActivityStartCallback { + @Rule + public PaymentRequestTestRule mPaymentRequestTestRule = + new PaymentRequestTestRule("payment_request_bobpay_and_cards_test.html", this); @Override public void onMainActivityStarted() @@ -37,38 +52,42 @@ * Tests that the Payment Request is cancelled if the user has no credit card and the proper * command line flag is set. */ + @Test @MediumTest @Feature({"Payments"}) @CommandLineFlags.Add("enable-features=NoCreditCardAbort") public void testAbortIfNoCard_Enabled_NoApp() throws InterruptedException, ExecutionException, TimeoutException { - openPageAndClickBuyAndWait(getShowFailed()); - expectResultContains(new String[] {"The payment method is not supported"}); + mPaymentRequestTestRule.openPageAndClickBuyAndWait(mPaymentRequestTestRule.getShowFailed()); + mPaymentRequestTestRule.expectResultContains( + new String[] {"The payment method is not supported"}); } /** * Tests that the Payment Request UI is shown even if the user has no credit card and the proper * command line flag is set, if they have another payment app that is accepted by the merchant. */ + @Test @MediumTest @Feature({"Payments"}) @CommandLineFlags.Add("enable-features=NoCreditCardAbort") public void testAbortIfNoCard_Enabled_WithApp() throws InterruptedException, ExecutionException, TimeoutException { - installPaymentApp(HAVE_INSTRUMENTS, IMMEDIATE_RESPONSE); - triggerUIAndWait(getReadyToPay()); + mPaymentRequestTestRule.installPaymentApp(HAVE_INSTRUMENTS, IMMEDIATE_RESPONSE); + mPaymentRequestTestRule.triggerUIAndWait(mPaymentRequestTestRule.getReadyToPay()); } /** * Tests that the Payment Request UI is shown if the user has no credit card and the proper * command line flag is set. */ + @Test @MediumTest @Feature({"Payments"}) @CommandLineFlags.Add("disable-features=NoCreditCardAbort") public void testAbortIfNoCard_Disabled() throws InterruptedException, ExecutionException, TimeoutException { // Check that the Payment Request UI is shown. - triggerUIAndWait(getReadyForInput()); + mPaymentRequestTestRule.triggerUIAndWait(mPaymentRequestTestRule.getReadyForInput()); } }
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestFreeShippingTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestFreeShippingTest.java index f494f4f..3fd3d47 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestFreeShippingTest.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestFreeShippingTest.java
@@ -7,14 +7,24 @@ import android.content.DialogInterface; import android.support.test.filters.MediumTest; +import org.junit.Assert; +import org.junit.Rule; +import org.junit.Test; +import org.junit.runner.RunWith; + import org.chromium.base.ThreadUtils; import org.chromium.base.metrics.RecordHistogram; +import org.chromium.base.test.util.CommandLineFlags; import org.chromium.base.test.util.Feature; import org.chromium.base.test.util.FlakyTest; import org.chromium.chrome.R; +import org.chromium.chrome.browser.ChromeSwitches; import org.chromium.chrome.browser.autofill.AutofillTestHelper; import org.chromium.chrome.browser.autofill.PersonalDataManager.AutofillProfile; import org.chromium.chrome.browser.autofill.PersonalDataManager.CreditCard; +import org.chromium.chrome.browser.payments.PaymentRequestTestRule.MainActivityStartCallback; +import org.chromium.chrome.test.ChromeActivityTestRule; +import org.chromium.chrome.test.ChromeJUnit4ClassRunner; import java.util.concurrent.ExecutionException; import java.util.concurrent.TimeoutException; @@ -22,11 +32,15 @@ /** * A payment integration test for a merchant that provides free shipping regardless of address. */ -public class PaymentRequestFreeShippingTest extends PaymentRequestTestBase { - public PaymentRequestFreeShippingTest() { - // This merchant provides free shipping worldwide. - super("payment_request_free_shipping_test.html"); - } +@RunWith(ChromeJUnit4ClassRunner.class) +@CommandLineFlags.Add({ + ChromeSwitches.DISABLE_FIRST_RUN_EXPERIENCE, + ChromeActivityTestRule.DISABLE_NETWORK_PREDICTION_FLAG, +}) +public class PaymentRequestFreeShippingTest implements MainActivityStartCallback { + @Rule + public PaymentRequestTestRule mPaymentRequestTestRule = + new PaymentRequestTestRule("payment_request_free_shipping_test.html", this); @Override public void onMainActivityStarted() @@ -42,203 +56,243 @@ } /** Submit the shipping address to the merchant when the user clicks "Pay." */ + @Test @MediumTest @Feature({"Payments"}) public void testPay() throws InterruptedException, ExecutionException, TimeoutException { - triggerUIAndWait(getReadyToPay()); - clickAndWait(R.id.button_primary, getReadyForUnmaskInput()); - setTextInCardUnmaskDialogAndWait(R.id.card_unmask_input, "123", getReadyToUnmask()); - clickCardUnmaskButtonAndWait(DialogInterface.BUTTON_POSITIVE, getDismissed()); - expectResultContains(new String[] {"Jon Doe", "4111111111111111", "12", "2050", "visa", - "123", "Google", "340 Main St", "CA", "Los Angeles", "90291", "US", "en", - "freeShippingOption"}); + mPaymentRequestTestRule.triggerUIAndWait(mPaymentRequestTestRule.getReadyToPay()); + mPaymentRequestTestRule.clickAndWait( + R.id.button_primary, mPaymentRequestTestRule.getReadyForUnmaskInput()); + mPaymentRequestTestRule.setTextInCardUnmaskDialogAndWait( + R.id.card_unmask_input, "123", mPaymentRequestTestRule.getReadyToUnmask()); + mPaymentRequestTestRule.clickCardUnmaskButtonAndWait( + DialogInterface.BUTTON_POSITIVE, mPaymentRequestTestRule.getDismissed()); + mPaymentRequestTestRule.expectResultContains(new String[] {"Jon Doe", "4111111111111111", + "12", "2050", "visa", "123", "Google", "340 Main St", "CA", "Los Angeles", "90291", + "US", "en", "freeShippingOption"}); } /** Attempt to add an invalid address and cancel the transaction. */ + @Test @MediumTest @FlakyTest(message = "crbug.com/673371") @Feature({"Payments"}) public void testAddInvalidAddressAndCancel() throws InterruptedException, ExecutionException, TimeoutException { - triggerUIAndWait(getReadyToPay()); - clickInShippingSummaryAndWait(R.id.payments_section, getReadyForInput()); - clickInShippingAddressAndWait(R.id.payments_add_option_button, getReadyToEdit()); - clickInEditorAndWait(R.id.payments_edit_done_button, getEditorValidationError()); - clickInEditorAndWait(R.id.payments_edit_cancel_button, getReadyToPay()); - clickAndWait(R.id.close_button, getDismissed()); - expectResultContains(new String[] {"Request cancelled"}); + mPaymentRequestTestRule.triggerUIAndWait(mPaymentRequestTestRule.getReadyToPay()); + mPaymentRequestTestRule.clickInShippingSummaryAndWait( + R.id.payments_section, mPaymentRequestTestRule.getReadyForInput()); + mPaymentRequestTestRule.clickInShippingAddressAndWait( + R.id.payments_add_option_button, mPaymentRequestTestRule.getReadyToEdit()); + mPaymentRequestTestRule.clickInEditorAndWait( + R.id.payments_edit_done_button, mPaymentRequestTestRule.getEditorValidationError()); + mPaymentRequestTestRule.clickInEditorAndWait( + R.id.payments_edit_cancel_button, mPaymentRequestTestRule.getReadyToPay()); + mPaymentRequestTestRule.clickAndWait( + R.id.close_button, mPaymentRequestTestRule.getDismissed()); + mPaymentRequestTestRule.expectResultContains(new String[] {"Request cancelled"}); } /** Add a valid address and complete the transaction. */ + @Test @MediumTest @Feature({"Payments"}) public void testAddAddressAndPay() throws InterruptedException, ExecutionException, TimeoutException { - triggerUIAndWait(getReadyToPay()); - clickInShippingSummaryAndWait(R.id.payments_section, getReadyForInput()); - clickInShippingAddressAndWait(R.id.payments_add_option_button, getReadyToEdit()); - setTextInEditorAndWait(new String[] {"Bob", "Google", "1600 Amphitheatre Pkwy", - "Mountain View", "CA", "94043", "650-253-0000"}, - getEditorTextUpdate()); - clickInEditorAndWait(R.id.payments_edit_done_button, getReadyToPay()); - clickAndWait(R.id.button_primary, getReadyForUnmaskInput()); - setTextInCardUnmaskDialogAndWait(R.id.card_unmask_input, "123", getReadyToUnmask()); - clickCardUnmaskButtonAndWait(DialogInterface.BUTTON_POSITIVE, getDismissed()); - expectResultContains(new String[] {"Bob", "Google", "1600 Amphitheatre Pkwy", - "Mountain View", "CA", "94043", "+16502530000"}); + mPaymentRequestTestRule.triggerUIAndWait(mPaymentRequestTestRule.getReadyToPay()); + mPaymentRequestTestRule.clickInShippingSummaryAndWait( + R.id.payments_section, mPaymentRequestTestRule.getReadyForInput()); + mPaymentRequestTestRule.clickInShippingAddressAndWait( + R.id.payments_add_option_button, mPaymentRequestTestRule.getReadyToEdit()); + mPaymentRequestTestRule.setTextInEditorAndWait( + new String[] {"Bob", "Google", "1600 Amphitheatre Pkwy", "Mountain View", "CA", + "94043", "650-253-0000"}, + mPaymentRequestTestRule.getEditorTextUpdate()); + mPaymentRequestTestRule.clickInEditorAndWait( + R.id.payments_edit_done_button, mPaymentRequestTestRule.getReadyToPay()); + mPaymentRequestTestRule.clickAndWait( + R.id.button_primary, mPaymentRequestTestRule.getReadyForUnmaskInput()); + mPaymentRequestTestRule.setTextInCardUnmaskDialogAndWait( + R.id.card_unmask_input, "123", mPaymentRequestTestRule.getReadyToUnmask()); + mPaymentRequestTestRule.clickCardUnmaskButtonAndWait( + DialogInterface.BUTTON_POSITIVE, mPaymentRequestTestRule.getDismissed()); + mPaymentRequestTestRule.expectResultContains(new String[] {"Bob", "Google", + "1600 Amphitheatre Pkwy", "Mountain View", "CA", "94043", "+16502530000"}); } /** Change the country in the spinner, add a valid address, and complete the transaction. */ + @Test @MediumTest @Feature({"Payments"}) public void testChangeCountryAddAddressAndPay() throws InterruptedException, ExecutionException, TimeoutException { - triggerUIAndWait(getReadyToPay()); - clickInShippingSummaryAndWait(R.id.payments_section, getReadyForInput()); - clickInShippingAddressAndWait(R.id.payments_add_option_button, getReadyToEdit()); - setSpinnerSelectionInEditorAndWait(0 /* Afghanistan */, getReadyToEdit()); - setTextInEditorAndWait(new String[] {"Alice", "Supreme Court", "Airport Road", "Kabul", - "1043", "650-253-0000"}, - getEditorTextUpdate()); - clickInEditorAndWait(R.id.payments_edit_done_button, getReadyToPay()); - clickAndWait(R.id.button_primary, getReadyForUnmaskInput()); - setTextInCardUnmaskDialogAndWait(R.id.card_unmask_input, "123", getReadyToUnmask()); - clickCardUnmaskButtonAndWait(DialogInterface.BUTTON_POSITIVE, getDismissed()); - expectResultContains(new String[] { + mPaymentRequestTestRule.triggerUIAndWait(mPaymentRequestTestRule.getReadyToPay()); + mPaymentRequestTestRule.clickInShippingSummaryAndWait( + R.id.payments_section, mPaymentRequestTestRule.getReadyForInput()); + mPaymentRequestTestRule.clickInShippingAddressAndWait( + R.id.payments_add_option_button, mPaymentRequestTestRule.getReadyToEdit()); + mPaymentRequestTestRule.setSpinnerSelectionInEditorAndWait( + 0 /* Afghanistan */, mPaymentRequestTestRule.getReadyToEdit()); + mPaymentRequestTestRule.setTextInEditorAndWait( + new String[] { + "Alice", "Supreme Court", "Airport Road", "Kabul", "1043", "650-253-0000"}, + mPaymentRequestTestRule.getEditorTextUpdate()); + mPaymentRequestTestRule.clickInEditorAndWait( + R.id.payments_edit_done_button, mPaymentRequestTestRule.getReadyToPay()); + mPaymentRequestTestRule.clickAndWait( + R.id.button_primary, mPaymentRequestTestRule.getReadyForUnmaskInput()); + mPaymentRequestTestRule.setTextInCardUnmaskDialogAndWait( + R.id.card_unmask_input, "123", mPaymentRequestTestRule.getReadyToUnmask()); + mPaymentRequestTestRule.clickCardUnmaskButtonAndWait( + DialogInterface.BUTTON_POSITIVE, mPaymentRequestTestRule.getDismissed()); + mPaymentRequestTestRule.expectResultContains(new String[] { "Alice", "Supreme Court", "Airport Road", "Kabul", "1043", "+16502530000"}); } /** Quickly pressing on "add address" and then [X] should not crash. */ + @Test @MediumTest @Feature({"Payments"}) public void testQuickAddAddressAndCloseShouldNotCrash() throws InterruptedException, ExecutionException, TimeoutException { - triggerUIAndWait(getReadyToPay()); - clickInShippingSummaryAndWait(R.id.payments_section, getReadyForInput()); + mPaymentRequestTestRule.triggerUIAndWait(mPaymentRequestTestRule.getReadyToPay()); + mPaymentRequestTestRule.clickInShippingSummaryAndWait( + R.id.payments_section, mPaymentRequestTestRule.getReadyForInput()); // Quickly press on "add address" and then [X]. - int callCount = getReadyToEdit().getCallCount(); + int callCount = mPaymentRequestTestRule.getReadyToEdit().getCallCount(); ThreadUtils.runOnUiThreadBlocking(new Runnable() { @Override public void run() { - getPaymentRequestUI() + mPaymentRequestTestRule.getPaymentRequestUI() .getShippingAddressSectionForTest() .findViewById(R.id.payments_add_option_button) .performClick(); - getPaymentRequestUI() + mPaymentRequestTestRule.getPaymentRequestUI() .getDialogForTest() .findViewById(R.id.close_button) .performClick(); } }); - getReadyToEdit().waitForCallback(callCount); + mPaymentRequestTestRule.getReadyToEdit().waitForCallback(callCount); - clickInEditorAndWait(R.id.payments_edit_cancel_button, getReadyToPay()); - clickAndWait(R.id.close_button, getDismissed()); - expectResultContains(new String[] {"Request cancelled"}); + mPaymentRequestTestRule.clickInEditorAndWait( + R.id.payments_edit_cancel_button, mPaymentRequestTestRule.getReadyToPay()); + mPaymentRequestTestRule.clickAndWait( + R.id.close_button, mPaymentRequestTestRule.getDismissed()); + mPaymentRequestTestRule.expectResultContains(new String[] {"Request cancelled"}); } /** Quickly pressing on [X] and then "add address" should not crash. */ + @Test @MediumTest @Feature({"Payments"}) public void testQuickCloseAndAddAddressShouldNotCrash() throws InterruptedException, ExecutionException, TimeoutException { - triggerUIAndWait(getReadyToPay()); - clickInShippingSummaryAndWait(R.id.payments_section, getReadyForInput()); + mPaymentRequestTestRule.triggerUIAndWait(mPaymentRequestTestRule.getReadyToPay()); + mPaymentRequestTestRule.clickInShippingSummaryAndWait( + R.id.payments_section, mPaymentRequestTestRule.getReadyForInput()); // Quickly press on [X] and then "add address." - int callCount = getDismissed().getCallCount(); + int callCount = mPaymentRequestTestRule.getDismissed().getCallCount(); ThreadUtils.runOnUiThreadBlocking(new Runnable() { @Override public void run() { - getPaymentRequestUI() + mPaymentRequestTestRule.getPaymentRequestUI() .getDialogForTest() .findViewById(R.id.close_button) .performClick(); - getPaymentRequestUI() + mPaymentRequestTestRule.getPaymentRequestUI() .getShippingAddressSectionForTest() .findViewById(R.id.payments_add_option_button) .performClick(); } }); - getDismissed().waitForCallback(callCount); + mPaymentRequestTestRule.getDismissed().waitForCallback(callCount); - expectResultContains(new String[] {"Request cancelled"}); + mPaymentRequestTestRule.expectResultContains(new String[] {"Request cancelled"}); } /** Quickly pressing on "add address" and then "cancel" should not crash. */ + @Test @MediumTest @FlakyTest(message = "crbug.com/673371") @Feature({"Payments"}) public void testQuickAddAddressAndCancelShouldNotCrash() throws InterruptedException, ExecutionException, TimeoutException { - triggerUIAndWait(getReadyToPay()); - clickInShippingSummaryAndWait(R.id.payments_section, getReadyForInput()); + mPaymentRequestTestRule.triggerUIAndWait(mPaymentRequestTestRule.getReadyToPay()); + mPaymentRequestTestRule.clickInShippingSummaryAndWait( + R.id.payments_section, mPaymentRequestTestRule.getReadyForInput()); // Quickly press on "add address" and then "cancel." - int callCount = getReadyToEdit().getCallCount(); + int callCount = mPaymentRequestTestRule.getReadyToEdit().getCallCount(); ThreadUtils.runOnUiThreadBlocking(new Runnable() { @Override public void run() { - getPaymentRequestUI() + mPaymentRequestTestRule.getPaymentRequestUI() .getShippingAddressSectionForTest() .findViewById(R.id.payments_add_option_button) .performClick(); - getPaymentRequestUI() + mPaymentRequestTestRule.getPaymentRequestUI() .getDialogForTest() .findViewById(R.id.button_secondary) .performClick(); } }); - getReadyToEdit().waitForCallback(callCount); + mPaymentRequestTestRule.getReadyToEdit().waitForCallback(callCount); - clickInEditorAndWait(R.id.payments_edit_cancel_button, getReadyToPay()); - clickAndWait(R.id.close_button, getDismissed()); - expectResultContains(new String[] {"Request cancelled"}); + mPaymentRequestTestRule.clickInEditorAndWait( + R.id.payments_edit_cancel_button, mPaymentRequestTestRule.getReadyToPay()); + mPaymentRequestTestRule.clickAndWait( + R.id.close_button, mPaymentRequestTestRule.getDismissed()); + mPaymentRequestTestRule.expectResultContains(new String[] {"Request cancelled"}); } /** Quickly pressing on "cancel" and then "add address" should not crash. */ + @Test @MediumTest @Feature({"Payments"}) public void testQuickCancelAndAddAddressShouldNotCrash() throws InterruptedException, ExecutionException, TimeoutException { - triggerUIAndWait(getReadyToPay()); - clickInShippingSummaryAndWait(R.id.payments_section, getReadyForInput()); + mPaymentRequestTestRule.triggerUIAndWait(mPaymentRequestTestRule.getReadyToPay()); + mPaymentRequestTestRule.clickInShippingSummaryAndWait( + R.id.payments_section, mPaymentRequestTestRule.getReadyForInput()); // Quickly press on "cancel" and then "add address." - int callCount = getDismissed().getCallCount(); + int callCount = mPaymentRequestTestRule.getDismissed().getCallCount(); ThreadUtils.runOnUiThreadBlocking(new Runnable() { @Override public void run() { - getPaymentRequestUI() + mPaymentRequestTestRule.getPaymentRequestUI() .getDialogForTest() .findViewById(R.id.button_secondary) .performClick(); - getPaymentRequestUI() + mPaymentRequestTestRule.getPaymentRequestUI() .getShippingAddressSectionForTest() .findViewById(R.id.payments_add_option_button) .performClick(); } }); - getDismissed().waitForCallback(callCount); + mPaymentRequestTestRule.getDismissed().waitForCallback(callCount); - expectResultContains(new String[] {"Request cancelled"}); + mPaymentRequestTestRule.expectResultContains(new String[] {"Request cancelled"}); } /** * Test that starting a payment request that requires only the shipping address results in the * appropriate metric being logged in the PaymentRequest.RequestedInformation histogram. */ + @Test @MediumTest @Feature({"Payments"}) - public void testRequestedInformationMetric() throws InterruptedException, ExecutionException, - TimeoutException { + public void testRequestedInformationMetric() + throws InterruptedException, ExecutionException, TimeoutException { // Start the Payment Request. - triggerUIAndWait(getReadyToPay()); + mPaymentRequestTestRule.triggerUIAndWait(mPaymentRequestTestRule.getReadyToPay()); // Make sure that only the appropriate enum value was logged. for (int i = 0; i < PaymentRequestMetrics.REQUESTED_INFORMATION_MAX; ++i) { - assertEquals((i == PaymentRequestMetrics.REQUESTED_INFORMATION_SHIPPING ? 1 : 0), + Assert.assertEquals((i == PaymentRequestMetrics.REQUESTED_INFORMATION_SHIPPING ? 1 : 0), RecordHistogram.getHistogramValueCountForTesting( "PaymentRequest.RequestedInformation", i)); }
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestIdTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestIdTest.java index 6e45b0acd..4e0192e9 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestIdTest.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestIdTest.java
@@ -7,11 +7,20 @@ import android.content.DialogInterface; import android.support.test.filters.MediumTest; +import org.junit.Rule; +import org.junit.Test; +import org.junit.runner.RunWith; + +import org.chromium.base.test.util.CommandLineFlags; import org.chromium.base.test.util.Feature; import org.chromium.chrome.R; +import org.chromium.chrome.browser.ChromeSwitches; import org.chromium.chrome.browser.autofill.AutofillTestHelper; import org.chromium.chrome.browser.autofill.PersonalDataManager.AutofillProfile; import org.chromium.chrome.browser.autofill.PersonalDataManager.CreditCard; +import org.chromium.chrome.browser.payments.PaymentRequestTestRule.MainActivityStartCallback; +import org.chromium.chrome.test.ChromeActivityTestRule; +import org.chromium.chrome.test.ChromeJUnit4ClassRunner; import java.util.concurrent.ExecutionException; import java.util.concurrent.TimeoutException; @@ -20,10 +29,15 @@ * A payment integration test for verifying the PaymentResponse contains the * free-form identifier specified in PaymentDetailsInit. */ -public class PaymentRequestIdTest extends PaymentRequestTestBase { - public PaymentRequestIdTest() { - super("payment_request_id_test.html"); - } +@RunWith(ChromeJUnit4ClassRunner.class) +@CommandLineFlags.Add({ + ChromeSwitches.DISABLE_FIRST_RUN_EXPERIENCE, + ChromeActivityTestRule.DISABLE_NETWORK_PREDICTION_FLAG, +}) +public class PaymentRequestIdTest implements MainActivityStartCallback { + @Rule + public PaymentRequestTestRule mPaymentRequestTestRule = + new PaymentRequestTestRule("payment_request_id_test.html", this); @Override public void onMainActivityStarted() @@ -41,14 +55,18 @@ * Submit the payment information without shipping address or shipping options to the merchant * when the user clicks "Pay." */ + @Test @MediumTest @Feature({"Payments"}) public void testPaymentResponse() throws InterruptedException, ExecutionException, TimeoutException { - triggerUIAndWait(getReadyToPay()); - clickAndWait(R.id.button_primary, getReadyForUnmaskInput()); - setTextInCardUnmaskDialogAndWait(R.id.card_unmask_input, "123", getReadyToUnmask()); - clickCardUnmaskButtonAndWait(DialogInterface.BUTTON_POSITIVE, getDismissed()); - expectResultContains(new String[] {"my_payment_id"}); + mPaymentRequestTestRule.triggerUIAndWait(mPaymentRequestTestRule.getReadyToPay()); + mPaymentRequestTestRule.clickAndWait( + R.id.button_primary, mPaymentRequestTestRule.getReadyForUnmaskInput()); + mPaymentRequestTestRule.setTextInCardUnmaskDialogAndWait( + R.id.card_unmask_input, "123", mPaymentRequestTestRule.getReadyToUnmask()); + mPaymentRequestTestRule.clickCardUnmaskButtonAndWait( + DialogInterface.BUTTON_POSITIVE, mPaymentRequestTestRule.getDismissed()); + mPaymentRequestTestRule.expectResultContains(new String[] {"my_payment_id"}); } }
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestIncompleteContactDetailsAndFreeShippingTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestIncompleteContactDetailsAndFreeShippingTest.java index a7b40bde..0c00131 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestIncompleteContactDetailsAndFreeShippingTest.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestIncompleteContactDetailsAndFreeShippingTest.java
@@ -4,12 +4,25 @@ package org.chromium.chrome.browser.payments; +import static org.chromium.chrome.browser.payments.PaymentRequestTestRule.HAVE_INSTRUMENTS; +import static org.chromium.chrome.browser.payments.PaymentRequestTestRule.IMMEDIATE_RESPONSE; + import android.support.test.filters.MediumTest; +import org.junit.Assert; +import org.junit.Rule; +import org.junit.Test; +import org.junit.runner.RunWith; + +import org.chromium.base.test.util.CommandLineFlags; import org.chromium.base.test.util.Feature; import org.chromium.chrome.R; +import org.chromium.chrome.browser.ChromeSwitches; import org.chromium.chrome.browser.autofill.AutofillTestHelper; import org.chromium.chrome.browser.autofill.PersonalDataManager.AutofillProfile; +import org.chromium.chrome.browser.payments.PaymentRequestTestRule.MainActivityStartCallback; +import org.chromium.chrome.test.ChromeActivityTestRule; +import org.chromium.chrome.test.ChromeJUnit4ClassRunner; import java.util.concurrent.ExecutionException; import java.util.concurrent.TimeoutException; @@ -19,13 +32,16 @@ * a phone number and provides free shipping regardless of address, with the user having * incomplete information. */ +@RunWith(ChromeJUnit4ClassRunner.class) +@CommandLineFlags.Add({ + ChromeSwitches.DISABLE_FIRST_RUN_EXPERIENCE, + ChromeActivityTestRule.DISABLE_NETWORK_PREDICTION_FLAG, +}) public class PaymentRequestIncompleteContactDetailsAndFreeShippingTest - extends PaymentRequestTestBase { - public PaymentRequestIncompleteContactDetailsAndFreeShippingTest() { - // This merchant requests an email address and a phone number and provides free shipping - // worldwide. - super("payment_request_contact_details_and_free_shipping_test.html"); - } + implements MainActivityStartCallback { + @Rule + public PaymentRequestTestRule mPaymentRequestTestRule = new PaymentRequestTestRule( + "payment_request_contact_details_and_free_shipping_test.html", this); @Override public void onMainActivityStarted() @@ -37,68 +53,89 @@ "340 Main St", "CA", "Los Angeles", "", "90291", "", "US", "" /* invalid phone number */, "jon.doe@google.com", "en-US")); - installPaymentApp(HAVE_INSTRUMENTS, IMMEDIATE_RESPONSE); + mPaymentRequestTestRule.installPaymentApp(HAVE_INSTRUMENTS, IMMEDIATE_RESPONSE); } /** Update the shipping address with valid data and see that the contacts section is updated. */ + @Test @MediumTest @Feature({"Payments"}) public void testEditIncompleteShippingAndPay() throws InterruptedException, ExecutionException, TimeoutException { - triggerUIAndWait(getReadyForInput()); - clickInShippingSummaryAndWait(R.id.payments_section, getReadyForInput()); + mPaymentRequestTestRule.triggerUIAndWait(mPaymentRequestTestRule.getReadyForInput()); + mPaymentRequestTestRule.clickInShippingSummaryAndWait( + R.id.payments_section, mPaymentRequestTestRule.getReadyForInput()); - assertEquals("Jon Doe\njon.doe@google.com\nPhone number required", - getContactDetailsSuggestionLabel(0)); + Assert.assertEquals("Jon Doe\njon.doe@google.com\nPhone number required", + mPaymentRequestTestRule.getContactDetailsSuggestionLabel(0)); - assertTrue(getShippingAddressSuggestionLabel(0).contains("Phone number required")); - clickInShippingAddressAndWait(R.id.payments_first_radio_button, getReadyToEdit()); - setTextInEditorAndWait(new String[] {"Jon Doe", "Google", "340 Main St", "Los Angeles", - "CA", "90291", "650-253-0000"}, - getEditorTextUpdate()); + Assert.assertTrue(mPaymentRequestTestRule.getShippingAddressSuggestionLabel(0).contains( + "Phone number required")); + mPaymentRequestTestRule.clickInShippingAddressAndWait( + R.id.payments_first_radio_button, mPaymentRequestTestRule.getReadyToEdit()); + mPaymentRequestTestRule.setTextInEditorAndWait( + new String[] {"Jon Doe", "Google", "340 Main St", "Los Angeles", "CA", "90291", + "650-253-0000"}, + mPaymentRequestTestRule.getEditorTextUpdate()); // The contact is now complete, but not selected. - clickInEditorAndWait(R.id.payments_edit_done_button, getReadyForInput()); + mPaymentRequestTestRule.clickInEditorAndWait( + R.id.payments_edit_done_button, mPaymentRequestTestRule.getReadyForInput()); // We select it. - clickInContactInfoAndWait(R.id.payments_section, getReadyForInput()); - assertEquals("Jon Doe\n+1 650-253-0000\njon.doe@google.com", - getContactDetailsSuggestionLabel(0)); - clickInContactInfoAndWait(R.id.payments_first_radio_button, getReadyToPay()); + mPaymentRequestTestRule.clickInContactInfoAndWait( + R.id.payments_section, mPaymentRequestTestRule.getReadyForInput()); + Assert.assertEquals("Jon Doe\n+1 650-253-0000\njon.doe@google.com", + mPaymentRequestTestRule.getContactDetailsSuggestionLabel(0)); + mPaymentRequestTestRule.clickInContactInfoAndWait( + R.id.payments_first_radio_button, mPaymentRequestTestRule.getReadyToPay()); - clickAndWait(R.id.button_primary, getDismissed()); - expectResultContains(new String[] {"Jon Doe", "+16502530000", "jon.doe@google.com"}); + mPaymentRequestTestRule.clickAndWait( + R.id.button_primary, mPaymentRequestTestRule.getDismissed()); + mPaymentRequestTestRule.expectResultContains( + new String[] {"Jon Doe", "+16502530000", "jon.doe@google.com"}); } /** Add a shipping address with valid data and see that the contacts section is updated. */ + @Test @MediumTest @Feature({"Payments"}) public void testEditIncompleteShippingAndContactAndPay() throws InterruptedException, ExecutionException, TimeoutException { - triggerUIAndWait(getReadyForInput()); - clickInShippingSummaryAndWait(R.id.payments_section, getReadyForInput()); + mPaymentRequestTestRule.triggerUIAndWait(mPaymentRequestTestRule.getReadyForInput()); + mPaymentRequestTestRule.clickInShippingSummaryAndWait( + R.id.payments_section, mPaymentRequestTestRule.getReadyForInput()); // There is an incomplete contact. - assertEquals("Jon Doe\njon.doe@google.com\nPhone number required", - getContactDetailsSuggestionLabel(0)); + Assert.assertEquals("Jon Doe\njon.doe@google.com\nPhone number required", + mPaymentRequestTestRule.getContactDetailsSuggestionLabel(0)); // Add a new Shipping Address and see that the contact section updates. - clickInShippingAddressAndWait(R.id.payments_add_option_button, getReadyToEdit()); - setTextInEditorAndWait(new String[] {"Jane Doe", "Edge Corp.", "111 Wall St.", "New York", - "NY", "10110", "650-253-0000"}, - getEditorTextUpdate()); - clickInEditorAndWait(R.id.payments_edit_done_button, getReadyForInput()); - assertEquals("Jon Doe\njon.doe@google.com\nPhone number required", - getContactDetailsSuggestionLabel(0)); - assertEquals( - "Jane Doe\n+1 650-253-0000\nEmail required", getContactDetailsSuggestionLabel(1)); + mPaymentRequestTestRule.clickInShippingAddressAndWait( + R.id.payments_add_option_button, mPaymentRequestTestRule.getReadyToEdit()); + mPaymentRequestTestRule.setTextInEditorAndWait( + new String[] {"Jane Doe", "Edge Corp.", "111 Wall St.", "New York", "NY", "10110", + "650-253-0000"}, + mPaymentRequestTestRule.getEditorTextUpdate()); + mPaymentRequestTestRule.clickInEditorAndWait( + R.id.payments_edit_done_button, mPaymentRequestTestRule.getReadyForInput()); + Assert.assertEquals("Jon Doe\njon.doe@google.com\nPhone number required", + mPaymentRequestTestRule.getContactDetailsSuggestionLabel(0)); + Assert.assertEquals("Jane Doe\n+1 650-253-0000\nEmail required", + mPaymentRequestTestRule.getContactDetailsSuggestionLabel(1)); // Now edit the first contact and pay. - clickInContactInfoAndWait(R.id.payments_section, getReadyForInput()); - clickInContactInfoAndWait(R.id.payments_first_radio_button, getReadyToEdit()); - setTextInEditorAndWait(new String[] {"Jon Doe", "650-253-0000", "jon.doe@google.com"}, - getEditorTextUpdate()); - clickInEditorAndWait(R.id.payments_edit_done_button, getReadyToPay()); + mPaymentRequestTestRule.clickInContactInfoAndWait( + R.id.payments_section, mPaymentRequestTestRule.getReadyForInput()); + mPaymentRequestTestRule.clickInContactInfoAndWait( + R.id.payments_first_radio_button, mPaymentRequestTestRule.getReadyToEdit()); + mPaymentRequestTestRule.setTextInEditorAndWait( + new String[] {"Jon Doe", "650-253-0000", "jon.doe@google.com"}, + mPaymentRequestTestRule.getEditorTextUpdate()); + mPaymentRequestTestRule.clickInEditorAndWait( + R.id.payments_edit_done_button, mPaymentRequestTestRule.getReadyToPay()); - clickAndWait(R.id.button_primary, getDismissed()); - expectResultContains(new String[] {"Jon Doe", "+16502530000", "jon.doe@google.com"}); + mPaymentRequestTestRule.clickAndWait( + R.id.button_primary, mPaymentRequestTestRule.getDismissed()); + mPaymentRequestTestRule.expectResultContains( + new String[] {"Jon Doe", "+16502530000", "jon.doe@google.com"}); } }
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestIncompleteContactDetailsTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestIncompleteContactDetailsTest.java index b9aa2df..957cad6 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestIncompleteContactDetailsTest.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestIncompleteContactDetailsTest.java
@@ -4,13 +4,26 @@ package org.chromium.chrome.browser.payments; +import static org.chromium.chrome.browser.payments.PaymentRequestTestRule.HAVE_INSTRUMENTS; +import static org.chromium.chrome.browser.payments.PaymentRequestTestRule.IMMEDIATE_RESPONSE; + import android.support.test.filters.MediumTest; +import org.junit.Assert; +import org.junit.Rule; +import org.junit.Test; +import org.junit.runner.RunWith; + +import org.chromium.base.test.util.CommandLineFlags; import org.chromium.base.test.util.Feature; import org.chromium.chrome.R; +import org.chromium.chrome.browser.ChromeSwitches; import org.chromium.chrome.browser.autofill.AutofillTestHelper; import org.chromium.chrome.browser.autofill.PersonalDataManager.AutofillProfile; +import org.chromium.chrome.browser.payments.PaymentRequestTestRule.MainActivityStartCallback; import org.chromium.chrome.browser.payments.ui.PaymentRequestSection; +import org.chromium.chrome.test.ChromeActivityTestRule; +import org.chromium.chrome.test.ChromeJUnit4ClassRunner; import java.util.concurrent.ExecutionException; import java.util.concurrent.TimeoutException; @@ -19,12 +32,15 @@ * A payment integration test for a merchant that requests contact details from a user that has * incomplete contact details stored on disk. */ -public class PaymentRequestIncompleteContactDetailsTest extends PaymentRequestTestBase { - public PaymentRequestIncompleteContactDetailsTest() { - // This merchant requests both a phone number and an email address. We set the user's email - // address as invalid, so all tests start in "ready for input" state. - super("payment_request_contact_details_test.html"); - } +@RunWith(ChromeJUnit4ClassRunner.class) +@CommandLineFlags.Add({ + ChromeSwitches.DISABLE_FIRST_RUN_EXPERIENCE, + ChromeActivityTestRule.DISABLE_NETWORK_PREDICTION_FLAG, +}) +public class PaymentRequestIncompleteContactDetailsTest implements MainActivityStartCallback { + @Rule + public PaymentRequestTestRule mPaymentRequestTestRule = + new PaymentRequestTestRule("payment_request_contact_details_test.html", this); @Override public void onMainActivityStarted() @@ -35,69 +51,92 @@ "340 Main St", "CA", "Los Angeles", "", "90291", "", "US", "333-333-3333", "jon.doe" /* invalid email address */, "en-US")); - installPaymentApp(HAVE_INSTRUMENTS, IMMEDIATE_RESPONSE); + mPaymentRequestTestRule.installPaymentApp(HAVE_INSTRUMENTS, IMMEDIATE_RESPONSE); } /** Attempt to update the contact information with invalid data and cancel the transaction. */ + @Test @MediumTest @Feature({"Payments"}) public void testEditIncompleteContactAndCancel() throws InterruptedException, ExecutionException, TimeoutException { // Not ready to pay since Contact email is invalid. - triggerUIAndWait(getReadyForInput()); + mPaymentRequestTestRule.triggerUIAndWait(mPaymentRequestTestRule.getReadyForInput()); // Check that there is a selected payment method (makes sure we are not ready to pay because // of the Contact Details). - expectPaymentMethodRowIsSelected(0); + mPaymentRequestTestRule.expectPaymentMethodRowIsSelected(0); // Updating contact with an invalid value and cancelling means we're still not // ready to pay (the value is still the original value). - clickInContactInfoAndWait(R.id.payments_section, getReadyForInput()); - clickInContactInfoAndWait(R.id.payments_first_radio_button, getReadyToEdit()); - setTextInEditorAndWait(new String[] {"", "---", "jane.jones"}, getEditorTextUpdate()); - clickInEditorAndWait(R.id.payments_edit_done_button, getEditorValidationError()); + mPaymentRequestTestRule.clickInContactInfoAndWait( + R.id.payments_section, mPaymentRequestTestRule.getReadyForInput()); + mPaymentRequestTestRule.clickInContactInfoAndWait( + R.id.payments_first_radio_button, mPaymentRequestTestRule.getReadyToEdit()); + mPaymentRequestTestRule.setTextInEditorAndWait(new String[] {"", "---", "jane.jones"}, + mPaymentRequestTestRule.getEditorTextUpdate()); + mPaymentRequestTestRule.clickInEditorAndWait( + R.id.payments_edit_done_button, mPaymentRequestTestRule.getEditorValidationError()); // The section collapses and the [CHOOSE] button is active. - clickInEditorAndWait(R.id.payments_edit_cancel_button, getReadyForInput()); - assertEquals(PaymentRequestSection.EDIT_BUTTON_CHOOSE, getContactDetailsButtonState()); + mPaymentRequestTestRule.clickInEditorAndWait( + R.id.payments_edit_cancel_button, mPaymentRequestTestRule.getReadyForInput()); + Assert.assertEquals(PaymentRequestSection.EDIT_BUTTON_CHOOSE, + mPaymentRequestTestRule.getContactDetailsButtonState()); - clickAndWait(R.id.close_button, getDismissed()); - expectResultContains(new String[] {"Request cancelled"}); + mPaymentRequestTestRule.clickAndWait( + R.id.close_button, mPaymentRequestTestRule.getDismissed()); + mPaymentRequestTestRule.expectResultContains(new String[] {"Request cancelled"}); } /** Attempt to add invalid contact info alongside the already invalid info, and cancel. */ + @Test @MediumTest @Feature({"Payments"}) public void testAddIncompleteContactAndCancel() throws InterruptedException, ExecutionException, TimeoutException { // Not ready to pay since Contact email is invalid. - triggerUIAndWait(getReadyForInput()); + mPaymentRequestTestRule.triggerUIAndWait(mPaymentRequestTestRule.getReadyForInput()); // Check that there is a selected payment method (makes sure we are not ready to pay because // of the Contact Details). - expectPaymentMethodRowIsSelected(0); + mPaymentRequestTestRule.expectPaymentMethodRowIsSelected(0); // Adding contact with an invalid value and cancelling means we're still not // ready to pay (the value is still the original value). - clickInContactInfoAndWait(R.id.payments_section, getReadyForInput()); - clickInContactInfoAndWait(R.id.payments_add_option_button, getReadyToEdit()); - setTextInEditorAndWait(new String[] {"", "---", "jane.jones"}, getEditorTextUpdate()); - clickInEditorAndWait(R.id.payments_edit_done_button, getEditorValidationError()); + mPaymentRequestTestRule.clickInContactInfoAndWait( + R.id.payments_section, mPaymentRequestTestRule.getReadyForInput()); + mPaymentRequestTestRule.clickInContactInfoAndWait( + R.id.payments_add_option_button, mPaymentRequestTestRule.getReadyToEdit()); + mPaymentRequestTestRule.setTextInEditorAndWait(new String[] {"", "---", "jane.jones"}, + mPaymentRequestTestRule.getEditorTextUpdate()); + mPaymentRequestTestRule.clickInEditorAndWait( + R.id.payments_edit_done_button, mPaymentRequestTestRule.getEditorValidationError()); // The section collapses and the [CHOOSE] button is active. - clickInEditorAndWait(R.id.payments_edit_cancel_button, getReadyForInput()); - assertEquals(PaymentRequestSection.EDIT_BUTTON_CHOOSE, getContactDetailsButtonState()); + mPaymentRequestTestRule.clickInEditorAndWait( + R.id.payments_edit_cancel_button, mPaymentRequestTestRule.getReadyForInput()); + Assert.assertEquals(PaymentRequestSection.EDIT_BUTTON_CHOOSE, + mPaymentRequestTestRule.getContactDetailsButtonState()); - clickAndWait(R.id.close_button, getDismissed()); - expectResultContains(new String[] {"Request cancelled"}); + mPaymentRequestTestRule.clickAndWait( + R.id.close_button, mPaymentRequestTestRule.getDismissed()); + mPaymentRequestTestRule.expectResultContains(new String[] {"Request cancelled"}); } /** Update the contact information with valid data and provide that to the merchant. */ + @Test @MediumTest @Feature({"Payments"}) public void testEditIncompleteContactAndPay() throws InterruptedException, ExecutionException, TimeoutException { - triggerUIAndWait(getReadyForInput()); - clickInContactInfoAndWait(R.id.payments_section, getReadyForInput()); - clickInContactInfoAndWait(R.id.payments_first_radio_button, getReadyToEdit()); - setTextInEditorAndWait(new String[] {"Jon Doe", "555-555-5555", "jon.doe@google.com"}, - getEditorTextUpdate()); - clickInEditorAndWait(R.id.payments_edit_done_button, getReadyToPay()); - clickAndWait(R.id.button_primary, getDismissed()); - expectResultContains(new String[] {"Jon Doe", "+15555555555", "jon.doe@google.com"}); + mPaymentRequestTestRule.triggerUIAndWait(mPaymentRequestTestRule.getReadyForInput()); + mPaymentRequestTestRule.clickInContactInfoAndWait( + R.id.payments_section, mPaymentRequestTestRule.getReadyForInput()); + mPaymentRequestTestRule.clickInContactInfoAndWait( + R.id.payments_first_radio_button, mPaymentRequestTestRule.getReadyToEdit()); + mPaymentRequestTestRule.setTextInEditorAndWait( + new String[] {"Jon Doe", "555-555-5555", "jon.doe@google.com"}, + mPaymentRequestTestRule.getEditorTextUpdate()); + mPaymentRequestTestRule.clickInEditorAndWait( + R.id.payments_edit_done_button, mPaymentRequestTestRule.getReadyToPay()); + mPaymentRequestTestRule.clickAndWait( + R.id.button_primary, mPaymentRequestTestRule.getDismissed()); + mPaymentRequestTestRule.expectResultContains( + new String[] {"Jon Doe", "+15555555555", "jon.doe@google.com"}); } }
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestIncompleteEmailTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestIncompleteEmailTest.java index 7167818..afc378e 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestIncompleteEmailTest.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestIncompleteEmailTest.java
@@ -4,13 +4,26 @@ package org.chromium.chrome.browser.payments; +import static org.chromium.chrome.browser.payments.PaymentRequestTestRule.HAVE_INSTRUMENTS; +import static org.chromium.chrome.browser.payments.PaymentRequestTestRule.IMMEDIATE_RESPONSE; + import android.support.test.filters.MediumTest; +import org.junit.Assert; +import org.junit.Rule; +import org.junit.Test; +import org.junit.runner.RunWith; + +import org.chromium.base.test.util.CommandLineFlags; import org.chromium.base.test.util.Feature; import org.chromium.chrome.R; +import org.chromium.chrome.browser.ChromeSwitches; import org.chromium.chrome.browser.autofill.AutofillTestHelper; import org.chromium.chrome.browser.autofill.PersonalDataManager.AutofillProfile; +import org.chromium.chrome.browser.payments.PaymentRequestTestRule.MainActivityStartCallback; import org.chromium.chrome.browser.payments.ui.PaymentRequestSection; +import org.chromium.chrome.test.ChromeActivityTestRule; +import org.chromium.chrome.test.ChromeJUnit4ClassRunner; import java.util.concurrent.ExecutionException; import java.util.concurrent.TimeoutException; @@ -19,12 +32,15 @@ * A payment integration test for a merchant that requests email address from a user that has * incomplete email address stored on disk. */ -public class PaymentRequestIncompleteEmailTest extends PaymentRequestTestBase { - public PaymentRequestIncompleteEmailTest() { - // This merchant requests an email address. We set the user's email as invalid, so all tests - // start in "ready for input" state. - super("payment_request_email_test.html"); - } +@RunWith(ChromeJUnit4ClassRunner.class) +@CommandLineFlags.Add({ + ChromeSwitches.DISABLE_FIRST_RUN_EXPERIENCE, + ChromeActivityTestRule.DISABLE_NETWORK_PREDICTION_FLAG, +}) +public class PaymentRequestIncompleteEmailTest implements MainActivityStartCallback { + @Rule + public PaymentRequestTestRule mPaymentRequestTestRule = + new PaymentRequestTestRule("payment_request_email_test.html", this); @Override public void onMainActivityStarted() @@ -35,67 +51,89 @@ "340 Main St", "CA", "Los Angeles", "", "90291", "", "US", "555-555-5555", "jon.doe" /* invalid email address */, "en-US")); - installPaymentApp(HAVE_INSTRUMENTS, IMMEDIATE_RESPONSE); + mPaymentRequestTestRule.installPaymentApp(HAVE_INSTRUMENTS, IMMEDIATE_RESPONSE); } /** Attempt to update the email with invalid data and cancel the transaction. */ + @Test @MediumTest @Feature({"Payments"}) public void testEditIncompleteEmailAndCancel() throws InterruptedException, ExecutionException, TimeoutException { // Not ready to pay since Contact email is invalid. - triggerUIAndWait(getReadyForInput()); + mPaymentRequestTestRule.triggerUIAndWait(mPaymentRequestTestRule.getReadyForInput()); // Check that there is a selected payment method (makes sure we are not ready to pay because // of the Contact Details). - expectPaymentMethodRowIsSelected(0); + mPaymentRequestTestRule.expectPaymentMethodRowIsSelected(0); // Updating contact with an invalid value and cancelling means we're still not // ready to pay (the value is still the original value). - clickInContactInfoAndWait(R.id.payments_section, getReadyForInput()); - clickInContactInfoAndWait(R.id.payments_first_radio_button, getReadyToEdit()); - setTextInEditorAndWait(new String[] {"gmail.com"}, getEditorTextUpdate()); - clickInEditorAndWait(R.id.payments_edit_done_button, getEditorValidationError()); - clickInEditorAndWait(R.id.payments_edit_cancel_button, getReadyForInput()); - assertEquals(PaymentRequestSection.EDIT_BUTTON_CHOOSE, getContactDetailsButtonState()); + mPaymentRequestTestRule.clickInContactInfoAndWait( + R.id.payments_section, mPaymentRequestTestRule.getReadyForInput()); + mPaymentRequestTestRule.clickInContactInfoAndWait( + R.id.payments_first_radio_button, mPaymentRequestTestRule.getReadyToEdit()); + mPaymentRequestTestRule.setTextInEditorAndWait( + new String[] {"gmail.com"}, mPaymentRequestTestRule.getEditorTextUpdate()); + mPaymentRequestTestRule.clickInEditorAndWait( + R.id.payments_edit_done_button, mPaymentRequestTestRule.getEditorValidationError()); + mPaymentRequestTestRule.clickInEditorAndWait( + R.id.payments_edit_cancel_button, mPaymentRequestTestRule.getReadyForInput()); + Assert.assertEquals(PaymentRequestSection.EDIT_BUTTON_CHOOSE, + mPaymentRequestTestRule.getContactDetailsButtonState()); - clickAndWait(R.id.close_button, getDismissed()); - expectResultContains(new String[] {"Request cancelled"}); + mPaymentRequestTestRule.clickAndWait( + R.id.close_button, mPaymentRequestTestRule.getDismissed()); + mPaymentRequestTestRule.expectResultContains(new String[] {"Request cancelled"}); } /** Attempt to add an invalid email alongside the already invalid data and cancel. */ + @Test @MediumTest @Feature({"Payments"}) public void testAddIncompleteEmailAndCancel() throws InterruptedException, ExecutionException, TimeoutException { // Not ready to pay since Contact email is invalid. - triggerUIAndWait(getReadyForInput()); + mPaymentRequestTestRule.triggerUIAndWait(mPaymentRequestTestRule.getReadyForInput()); // Check that there is a selected payment method (makes sure we are not ready to pay because // of the Contact Details). - expectPaymentMethodRowIsSelected(0); + mPaymentRequestTestRule.expectPaymentMethodRowIsSelected(0); // Updating contact with an invalid value and cancelling means we're still not // ready to pay (the value is still the original value). - clickInContactInfoAndWait(R.id.payments_section, getReadyForInput()); - clickInContactInfoAndWait(R.id.payments_add_option_button, getReadyToEdit()); - setTextInEditorAndWait(new String[] {"gmail.com"}, getEditorTextUpdate()); - clickInEditorAndWait(R.id.payments_edit_done_button, getEditorValidationError()); + mPaymentRequestTestRule.clickInContactInfoAndWait( + R.id.payments_section, mPaymentRequestTestRule.getReadyForInput()); + mPaymentRequestTestRule.clickInContactInfoAndWait( + R.id.payments_add_option_button, mPaymentRequestTestRule.getReadyToEdit()); + mPaymentRequestTestRule.setTextInEditorAndWait( + new String[] {"gmail.com"}, mPaymentRequestTestRule.getEditorTextUpdate()); + mPaymentRequestTestRule.clickInEditorAndWait( + R.id.payments_edit_done_button, mPaymentRequestTestRule.getEditorValidationError()); // The section collapses and the [CHOOSE] button is active. - clickInEditorAndWait(R.id.payments_edit_cancel_button, getReadyForInput()); - assertEquals(PaymentRequestSection.EDIT_BUTTON_CHOOSE, getContactDetailsButtonState()); + mPaymentRequestTestRule.clickInEditorAndWait( + R.id.payments_edit_cancel_button, mPaymentRequestTestRule.getReadyForInput()); + Assert.assertEquals(PaymentRequestSection.EDIT_BUTTON_CHOOSE, + mPaymentRequestTestRule.getContactDetailsButtonState()); - clickAndWait(R.id.close_button, getDismissed()); - expectResultContains(new String[] {"Request cancelled"}); + mPaymentRequestTestRule.clickAndWait( + R.id.close_button, mPaymentRequestTestRule.getDismissed()); + mPaymentRequestTestRule.expectResultContains(new String[] {"Request cancelled"}); } /** Update the email with valid data and provide that to the merchant. */ + @Test @MediumTest @Feature({"Payments"}) public void testEditIncompleteEmailAndPay() throws InterruptedException, ExecutionException, TimeoutException { - triggerUIAndWait(getReadyForInput()); - clickInContactInfoAndWait(R.id.payments_section, getReadyForInput()); - clickInContactInfoAndWait(R.id.payments_first_radio_button, getReadyToEdit()); - setTextInEditorAndWait(new String[] {"jon.doe@google.com"}, getEditorTextUpdate()); - clickInEditorAndWait(R.id.payments_edit_done_button, getReadyToPay()); - clickAndWait(R.id.button_primary, getDismissed()); - expectResultContains(new String[] {"jon.doe@google.com"}); + mPaymentRequestTestRule.triggerUIAndWait(mPaymentRequestTestRule.getReadyForInput()); + mPaymentRequestTestRule.clickInContactInfoAndWait( + R.id.payments_section, mPaymentRequestTestRule.getReadyForInput()); + mPaymentRequestTestRule.clickInContactInfoAndWait( + R.id.payments_first_radio_button, mPaymentRequestTestRule.getReadyToEdit()); + mPaymentRequestTestRule.setTextInEditorAndWait( + new String[] {"jon.doe@google.com"}, mPaymentRequestTestRule.getEditorTextUpdate()); + mPaymentRequestTestRule.clickInEditorAndWait( + R.id.payments_edit_done_button, mPaymentRequestTestRule.getReadyToPay()); + mPaymentRequestTestRule.clickAndWait( + R.id.button_primary, mPaymentRequestTestRule.getDismissed()); + mPaymentRequestTestRule.expectResultContains(new String[] {"jon.doe@google.com"}); } }
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestIncompletePhoneTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestIncompletePhoneTest.java index 1b123ef6..dc0921b 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestIncompletePhoneTest.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestIncompletePhoneTest.java
@@ -4,13 +4,26 @@ package org.chromium.chrome.browser.payments; +import static org.chromium.chrome.browser.payments.PaymentRequestTestRule.HAVE_INSTRUMENTS; +import static org.chromium.chrome.browser.payments.PaymentRequestTestRule.IMMEDIATE_RESPONSE; + import android.support.test.filters.MediumTest; +import org.junit.Assert; +import org.junit.Rule; +import org.junit.Test; +import org.junit.runner.RunWith; + +import org.chromium.base.test.util.CommandLineFlags; import org.chromium.base.test.util.Feature; import org.chromium.chrome.R; +import org.chromium.chrome.browser.ChromeSwitches; import org.chromium.chrome.browser.autofill.AutofillTestHelper; import org.chromium.chrome.browser.autofill.PersonalDataManager.AutofillProfile; +import org.chromium.chrome.browser.payments.PaymentRequestTestRule.MainActivityStartCallback; import org.chromium.chrome.browser.payments.ui.PaymentRequestSection; +import org.chromium.chrome.test.ChromeActivityTestRule; +import org.chromium.chrome.test.ChromeJUnit4ClassRunner; import java.util.concurrent.ExecutionException; import java.util.concurrent.TimeoutException; @@ -19,12 +32,15 @@ * A payment integration test for a merchant that requests phone number from a user that has * incomplete phone number stored on disk. */ -public class PaymentRequestIncompletePhoneTest extends PaymentRequestTestBase { - public PaymentRequestIncompletePhoneTest() { - // This merchant requests a phone number. We set the user's phone as invalid, so all tests - // start in "ready for input" state. - super("payment_request_phone_test.html"); - } +@RunWith(ChromeJUnit4ClassRunner.class) +@CommandLineFlags.Add({ + ChromeSwitches.DISABLE_FIRST_RUN_EXPERIENCE, + ChromeActivityTestRule.DISABLE_NETWORK_PREDICTION_FLAG, +}) +public class PaymentRequestIncompletePhoneTest implements MainActivityStartCallback { + @Rule + public PaymentRequestTestRule mPaymentRequestTestRule = + new PaymentRequestTestRule("payment_request_phone_test.html", this); @Override public void onMainActivityStarted() @@ -35,67 +51,89 @@ "340 Main St", "CA", "Los Angeles", "", "90291", "", "US", "+++" /* invalid phone */, "jon.doe@gmail.com", "en-US")); - installPaymentApp(HAVE_INSTRUMENTS, IMMEDIATE_RESPONSE); + mPaymentRequestTestRule.installPaymentApp(HAVE_INSTRUMENTS, IMMEDIATE_RESPONSE); } /** Attempt to update the phone number with invalid data and cancel the transaction. */ + @Test @MediumTest @Feature({"Payments"}) public void testEditIncompletePhoneAndCancel() throws InterruptedException, ExecutionException, TimeoutException { // Not ready to pay since Contact phone is invalid. - triggerUIAndWait(getReadyForInput()); + mPaymentRequestTestRule.triggerUIAndWait(mPaymentRequestTestRule.getReadyForInput()); // Check that there is a selected payment method (makes sure we are not ready to pay because // of the Contact Details). - expectPaymentMethodRowIsSelected(0); + mPaymentRequestTestRule.expectPaymentMethodRowIsSelected(0); // Updating contact with an invalid value and cancelling means we're still not // ready to pay (the value is still the original value). - clickInContactInfoAndWait(R.id.payments_section, getReadyForInput()); - clickInContactInfoAndWait(R.id.payments_first_radio_button, getReadyToEdit()); - setTextInEditorAndWait(new String[] {"---"}, getEditorTextUpdate()); - clickInEditorAndWait(R.id.payments_edit_done_button, getEditorValidationError()); - clickInEditorAndWait(R.id.payments_edit_cancel_button, getReadyForInput()); - assertEquals(PaymentRequestSection.EDIT_BUTTON_CHOOSE, getContactDetailsButtonState()); + mPaymentRequestTestRule.clickInContactInfoAndWait( + R.id.payments_section, mPaymentRequestTestRule.getReadyForInput()); + mPaymentRequestTestRule.clickInContactInfoAndWait( + R.id.payments_first_radio_button, mPaymentRequestTestRule.getReadyToEdit()); + mPaymentRequestTestRule.setTextInEditorAndWait( + new String[] {"---"}, mPaymentRequestTestRule.getEditorTextUpdate()); + mPaymentRequestTestRule.clickInEditorAndWait( + R.id.payments_edit_done_button, mPaymentRequestTestRule.getEditorValidationError()); + mPaymentRequestTestRule.clickInEditorAndWait( + R.id.payments_edit_cancel_button, mPaymentRequestTestRule.getReadyForInput()); + Assert.assertEquals(PaymentRequestSection.EDIT_BUTTON_CHOOSE, + mPaymentRequestTestRule.getContactDetailsButtonState()); - clickAndWait(R.id.close_button, getDismissed()); - expectResultContains(new String[] {"Request cancelled"}); + mPaymentRequestTestRule.clickAndWait( + R.id.close_button, mPaymentRequestTestRule.getDismissed()); + mPaymentRequestTestRule.expectResultContains(new String[] {"Request cancelled"}); } /** Attempt to add an invalid phone alongside the already invalid data and cancel. */ + @Test @MediumTest @Feature({"Payments"}) public void testAddIncompletePhoneAndCancel() throws InterruptedException, ExecutionException, TimeoutException { // Not ready to pay since Contact phone is invalid. - triggerUIAndWait(getReadyForInput()); + mPaymentRequestTestRule.triggerUIAndWait(mPaymentRequestTestRule.getReadyForInput()); // Check that there is a selected payment method (makes sure we are not ready to pay because // of the Contact Details). - expectPaymentMethodRowIsSelected(0); + mPaymentRequestTestRule.expectPaymentMethodRowIsSelected(0); // Updating contact with an invalid value and cancelling means we're still not // ready to pay (the value is still the original value). - clickInContactInfoAndWait(R.id.payments_section, getReadyForInput()); - clickInContactInfoAndWait(R.id.payments_add_option_button, getReadyToEdit()); - setTextInEditorAndWait(new String[] {"---"}, getEditorTextUpdate()); - clickInEditorAndWait(R.id.payments_edit_done_button, getEditorValidationError()); + mPaymentRequestTestRule.clickInContactInfoAndWait( + R.id.payments_section, mPaymentRequestTestRule.getReadyForInput()); + mPaymentRequestTestRule.clickInContactInfoAndWait( + R.id.payments_add_option_button, mPaymentRequestTestRule.getReadyToEdit()); + mPaymentRequestTestRule.setTextInEditorAndWait( + new String[] {"---"}, mPaymentRequestTestRule.getEditorTextUpdate()); + mPaymentRequestTestRule.clickInEditorAndWait( + R.id.payments_edit_done_button, mPaymentRequestTestRule.getEditorValidationError()); // The section collapses and the [CHOOSE] button is active. - clickInEditorAndWait(R.id.payments_edit_cancel_button, getReadyForInput()); - assertEquals(PaymentRequestSection.EDIT_BUTTON_CHOOSE, getContactDetailsButtonState()); + mPaymentRequestTestRule.clickInEditorAndWait( + R.id.payments_edit_cancel_button, mPaymentRequestTestRule.getReadyForInput()); + Assert.assertEquals(PaymentRequestSection.EDIT_BUTTON_CHOOSE, + mPaymentRequestTestRule.getContactDetailsButtonState()); - clickAndWait(R.id.close_button, getDismissed()); - expectResultContains(new String[] {"Request cancelled"}); + mPaymentRequestTestRule.clickAndWait( + R.id.close_button, mPaymentRequestTestRule.getDismissed()); + mPaymentRequestTestRule.expectResultContains(new String[] {"Request cancelled"}); } /** Update the phone with valid data and provide that to the merchant. */ + @Test @MediumTest @Feature({"Payments"}) public void testEditIncompletePhoneAndPay() throws InterruptedException, ExecutionException, TimeoutException { - triggerUIAndWait(getReadyForInput()); - clickInContactInfoAndWait(R.id.payments_section, getReadyForInput()); - clickInContactInfoAndWait(R.id.payments_first_radio_button, getReadyToEdit()); - setTextInEditorAndWait(new String[] {"514-555-5555"}, getEditorTextUpdate()); - clickInEditorAndWait(R.id.payments_edit_done_button, getReadyToPay()); - clickAndWait(R.id.button_primary, getDismissed()); - expectResultContains(new String[] {"+15145555555"}); + mPaymentRequestTestRule.triggerUIAndWait(mPaymentRequestTestRule.getReadyForInput()); + mPaymentRequestTestRule.clickInContactInfoAndWait( + R.id.payments_section, mPaymentRequestTestRule.getReadyForInput()); + mPaymentRequestTestRule.clickInContactInfoAndWait( + R.id.payments_first_radio_button, mPaymentRequestTestRule.getReadyToEdit()); + mPaymentRequestTestRule.setTextInEditorAndWait( + new String[] {"514-555-5555"}, mPaymentRequestTestRule.getEditorTextUpdate()); + mPaymentRequestTestRule.clickInEditorAndWait( + R.id.payments_edit_done_button, mPaymentRequestTestRule.getReadyToPay()); + mPaymentRequestTestRule.clickAndWait( + R.id.button_primary, mPaymentRequestTestRule.getDismissed()); + mPaymentRequestTestRule.expectResultContains(new String[] {"+15145555555"}); } }
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestIncompleteServerCardTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestIncompleteServerCardTest.java index de2141f..703de2e 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestIncompleteServerCardTest.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestIncompleteServerCardTest.java
@@ -7,11 +7,20 @@ import android.content.DialogInterface; import android.support.test.filters.MediumTest; +import org.junit.Rule; +import org.junit.Test; +import org.junit.runner.RunWith; + +import org.chromium.base.test.util.CommandLineFlags; import org.chromium.base.test.util.Feature; import org.chromium.chrome.R; +import org.chromium.chrome.browser.ChromeSwitches; import org.chromium.chrome.browser.autofill.AutofillTestHelper; import org.chromium.chrome.browser.autofill.PersonalDataManager.AutofillProfile; import org.chromium.chrome.browser.autofill.PersonalDataManager.CreditCard; +import org.chromium.chrome.browser.payments.PaymentRequestTestRule.MainActivityStartCallback; +import org.chromium.chrome.test.ChromeActivityTestRule; +import org.chromium.chrome.test.ChromeJUnit4ClassRunner; import java.util.concurrent.ExecutionException; import java.util.concurrent.TimeoutException; @@ -19,12 +28,17 @@ /** * A test for paying with an incomplete server card. */ -public class PaymentRequestIncompleteServerCardTest extends PaymentRequestTestBase { - private static final int FIRST_BILLING_ADDRESS = 0; +@RunWith(ChromeJUnit4ClassRunner.class) +@CommandLineFlags.Add({ + ChromeSwitches.DISABLE_FIRST_RUN_EXPERIENCE, + ChromeActivityTestRule.DISABLE_NETWORK_PREDICTION_FLAG, +}) +public class PaymentRequestIncompleteServerCardTest implements MainActivityStartCallback { + @Rule + public PaymentRequestTestRule mPaymentRequestTestRule = + new PaymentRequestTestRule("payment_request_no_shipping_test.html", this); - public PaymentRequestIncompleteServerCardTest() { - super("payment_request_no_shipping_test.html"); - } + private static final int FIRST_BILLING_ADDRESS = 0; @Override public void onMainActivityStarted() @@ -39,19 +53,27 @@ } /** Click [PAY] and dismiss the card unmask dialog. */ + @Test @MediumTest @Feature({"Payments"}) - public void testPayAndDontUnmask() throws InterruptedException, ExecutionException, - TimeoutException { - triggerUIAndWait(getReadyForInput()); - clickInPaymentMethodAndWait(R.id.payments_section, getReadyForInput()); - clickInPaymentMethodAndWait(R.id.payments_first_radio_button, getReadyToEdit()); - setSpinnerSelectionsInCardEditorAndWait( - new int[] {FIRST_BILLING_ADDRESS}, getBillingAddressChangeProcessed()); - clickInCardEditorAndWait(R.id.payments_edit_done_button, getReadyToPay()); - clickAndWait(R.id.button_primary, getReadyForUnmaskInput()); - clickCardUnmaskButtonAndWait(DialogInterface.BUTTON_NEGATIVE, getReadyToPay()); - clickAndWait(R.id.button_secondary, getDismissed()); - expectResultContains(new String[] {"Request cancelled"}); + public void testPayAndDontUnmask() + throws InterruptedException, ExecutionException, TimeoutException { + mPaymentRequestTestRule.triggerUIAndWait(mPaymentRequestTestRule.getReadyForInput()); + mPaymentRequestTestRule.clickInPaymentMethodAndWait( + R.id.payments_section, mPaymentRequestTestRule.getReadyForInput()); + mPaymentRequestTestRule.clickInPaymentMethodAndWait( + R.id.payments_first_radio_button, mPaymentRequestTestRule.getReadyToEdit()); + mPaymentRequestTestRule.setSpinnerSelectionsInCardEditorAndWait( + new int[] {FIRST_BILLING_ADDRESS}, + mPaymentRequestTestRule.getBillingAddressChangeProcessed()); + mPaymentRequestTestRule.clickInCardEditorAndWait( + R.id.payments_edit_done_button, mPaymentRequestTestRule.getReadyToPay()); + mPaymentRequestTestRule.clickAndWait( + R.id.button_primary, mPaymentRequestTestRule.getReadyForUnmaskInput()); + mPaymentRequestTestRule.clickCardUnmaskButtonAndWait( + DialogInterface.BUTTON_NEGATIVE, mPaymentRequestTestRule.getReadyToPay()); + mPaymentRequestTestRule.clickAndWait( + R.id.button_secondary, mPaymentRequestTestRule.getDismissed()); + mPaymentRequestTestRule.expectResultContains(new String[] {"Request cancelled"}); } }
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestJourneyLoggerTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestJourneyLoggerTest.java index 58abf0d2..6172c6c 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestJourneyLoggerTest.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestJourneyLoggerTest.java
@@ -4,15 +4,28 @@ package org.chromium.chrome.browser.payments; +import static org.chromium.chrome.browser.payments.PaymentRequestTestRule.DELAYED_RESPONSE; +import static org.chromium.chrome.browser.payments.PaymentRequestTestRule.NO_INSTRUMENTS; + import android.content.DialogInterface; import android.support.test.filters.MediumTest; +import org.junit.Assert; +import org.junit.Rule; +import org.junit.Test; +import org.junit.runner.RunWith; + import org.chromium.base.metrics.RecordHistogram; +import org.chromium.base.test.util.CommandLineFlags; import org.chromium.base.test.util.Feature; import org.chromium.chrome.R; +import org.chromium.chrome.browser.ChromeSwitches; import org.chromium.chrome.browser.autofill.AutofillTestHelper; import org.chromium.chrome.browser.autofill.PersonalDataManager.AutofillProfile; import org.chromium.chrome.browser.autofill.PersonalDataManager.CreditCard; +import org.chromium.chrome.browser.payments.PaymentRequestTestRule.MainActivityStartCallback; +import org.chromium.chrome.test.ChromeActivityTestRule; +import org.chromium.chrome.test.ChromeJUnit4ClassRunner; import java.util.concurrent.ExecutionException; import java.util.concurrent.TimeoutException; @@ -20,10 +33,15 @@ /** * A payment integration test to validate the logging of Payment Request metrics. */ -public class PaymentRequestJourneyLoggerTest extends PaymentRequestTestBase { - public PaymentRequestJourneyLoggerTest() { - super("payment_request_metrics_test.html"); - } +@RunWith(ChromeJUnit4ClassRunner.class) +@CommandLineFlags.Add({ + ChromeSwitches.DISABLE_FIRST_RUN_EXPERIENCE, + ChromeActivityTestRule.DISABLE_NETWORK_PREDICTION_FLAG, +}) +public class PaymentRequestJourneyLoggerTest implements MainActivityStartCallback { + @Rule + public PaymentRequestTestRule mPaymentRequestTestRule = + new PaymentRequestTestRule("payment_request_metrics_test.html", this); @Override public void onMainActivityStarted() @@ -48,331 +66,390 @@ /** * Expect that the number of shipping address suggestions was logged properly. */ + @Test @MediumTest @Feature({"Payments"}) public void testNumberOfSuggestionsShown_ShippingAddress_Completed() throws InterruptedException, ExecutionException, TimeoutException { // Complete a Payment Request with a credit card. - triggerUIAndWait("ccBuy", getReadyToPay()); - clickAndWait(R.id.button_primary, getReadyForUnmaskInput()); - setTextInCardUnmaskDialogAndWait(R.id.card_unmask_input, "123", getReadyToUnmask()); - clickCardUnmaskButtonAndWait(DialogInterface.BUTTON_POSITIVE, getDismissed()); + mPaymentRequestTestRule.triggerUIAndWait("ccBuy", mPaymentRequestTestRule.getReadyToPay()); + mPaymentRequestTestRule.clickAndWait( + R.id.button_primary, mPaymentRequestTestRule.getReadyForUnmaskInput()); + mPaymentRequestTestRule.setTextInCardUnmaskDialogAndWait( + R.id.card_unmask_input, "123", mPaymentRequestTestRule.getReadyToUnmask()); + mPaymentRequestTestRule.clickCardUnmaskButtonAndWait( + DialogInterface.BUTTON_POSITIVE, mPaymentRequestTestRule.getDismissed()); // Make sure the right number of suggestions were logged. - assertEquals( - 1, RecordHistogram.getHistogramValueCountForTesting( - "PaymentRequest.NumberOfSuggestionsShown.ShippingAddress.Completed", 2)); + Assert.assertEquals(1, + RecordHistogram.getHistogramValueCountForTesting( + "PaymentRequest.NumberOfSuggestionsShown.ShippingAddress.Completed", 2)); // Make sure no adds, edits or changes were logged. - assertEquals( - 1, RecordHistogram.getHistogramValueCountForTesting( - "PaymentRequest.NumberOfSelectionAdds.ShippingAddress.Completed", 0)); - assertEquals( - 1, RecordHistogram.getHistogramValueCountForTesting( - "PaymentRequest.NumberOfSelectionChanges.ShippingAddress.Completed", 0)); - assertEquals( - 1, RecordHistogram.getHistogramValueCountForTesting( - "PaymentRequest.NumberOfSelectionEdits.ShippingAddress.Completed", 0)); + Assert.assertEquals(1, + RecordHistogram.getHistogramValueCountForTesting( + "PaymentRequest.NumberOfSelectionAdds.ShippingAddress.Completed", 0)); + Assert.assertEquals(1, + RecordHistogram.getHistogramValueCountForTesting( + "PaymentRequest.NumberOfSelectionChanges.ShippingAddress.Completed", 0)); + Assert.assertEquals(1, + RecordHistogram.getHistogramValueCountForTesting( + "PaymentRequest.NumberOfSelectionEdits.ShippingAddress.Completed", 0)); } /** * Expect that the number of shipping address suggestions was logged properly. */ + @Test @MediumTest @Feature({"Payments"}) public void testNumberOfSuggestionsShown_ShippingAddress_AbortedByUser() throws InterruptedException, ExecutionException, TimeoutException { // Cancel the payment request. - triggerUIAndWait("ccBuy", getReadyToPay()); - clickAndWait(R.id.close_button, getDismissed()); + mPaymentRequestTestRule.triggerUIAndWait("ccBuy", mPaymentRequestTestRule.getReadyToPay()); + mPaymentRequestTestRule.clickAndWait( + R.id.close_button, mPaymentRequestTestRule.getDismissed()); // Wait for the histograms to be logged. Thread.sleep(200); // Make sure the right number of suggestions were logged. - assertEquals(1, + Assert.assertEquals(1, RecordHistogram.getHistogramValueCountForTesting( "PaymentRequest.NumberOfSuggestionsShown.ShippingAddress.UserAborted", 2)); // Make sure no adds, edits or changes were logged. - assertEquals( - 1, RecordHistogram.getHistogramValueCountForTesting( - "PaymentRequest.NumberOfSelectionAdds.ShippingAddress.UserAborted", 0)); - assertEquals(1, + Assert.assertEquals(1, + RecordHistogram.getHistogramValueCountForTesting( + "PaymentRequest.NumberOfSelectionAdds.ShippingAddress.UserAborted", 0)); + Assert.assertEquals(1, RecordHistogram.getHistogramValueCountForTesting( "PaymentRequest.NumberOfSelectionChanges.ShippingAddress.UserAborted", 0)); - assertEquals( - 1, RecordHistogram.getHistogramValueCountForTesting( - "PaymentRequest.NumberOfSelectionEdits.ShippingAddress.UserAborted", 0)); + Assert.assertEquals(1, + RecordHistogram.getHistogramValueCountForTesting( + "PaymentRequest.NumberOfSelectionEdits.ShippingAddress.UserAborted", 0)); } /** * Expect that the NumberOfSelectionEdits histogram gets logged properly for shipping addresses. */ + @Test @MediumTest @Feature({"Payments"}) public void testNumberOfSelectionEdits_ShippingAddress_Completed() throws InterruptedException, ExecutionException, TimeoutException { // Complete a Payment Request with a credit card. - triggerUIAndWait("ccBuy", getReadyToPay()); - clickInShippingSummaryAndWait(R.id.payments_section, getReadyForInput()); + mPaymentRequestTestRule.triggerUIAndWait("ccBuy", mPaymentRequestTestRule.getReadyToPay()); + mPaymentRequestTestRule.clickInShippingSummaryAndWait( + R.id.payments_section, mPaymentRequestTestRule.getReadyForInput()); // Select the incomplete address and edit it. - clickOnShippingAddressSuggestionOptionAndWait(1, getReadyToEdit()); - setTextInEditorAndWait( + mPaymentRequestTestRule.clickOnShippingAddressSuggestionOptionAndWait( + 1, mPaymentRequestTestRule.getReadyToEdit()); + mPaymentRequestTestRule.setTextInEditorAndWait( new String[] {"In Complete", "Google", "344 Main St", "CA", "Los Angeles"}, - getEditorTextUpdate()); - clickInEditorAndWait(R.id.payments_edit_done_button, getReadyToPay()); - clickAndWait(R.id.button_primary, getReadyForUnmaskInput()); - setTextInCardUnmaskDialogAndWait(R.id.card_unmask_input, "123", getReadyToUnmask()); - clickCardUnmaskButtonAndWait(DialogInterface.BUTTON_POSITIVE, getDismissed()); + mPaymentRequestTestRule.getEditorTextUpdate()); + mPaymentRequestTestRule.clickInEditorAndWait( + R.id.payments_edit_done_button, mPaymentRequestTestRule.getReadyToPay()); + mPaymentRequestTestRule.clickAndWait( + R.id.button_primary, mPaymentRequestTestRule.getReadyForUnmaskInput()); + mPaymentRequestTestRule.setTextInCardUnmaskDialogAndWait( + R.id.card_unmask_input, "123", mPaymentRequestTestRule.getReadyToUnmask()); + mPaymentRequestTestRule.clickCardUnmaskButtonAndWait( + DialogInterface.BUTTON_POSITIVE, mPaymentRequestTestRule.getDismissed()); // Make sure the edit was logged. - assertEquals( - 1, RecordHistogram.getHistogramValueCountForTesting( - "PaymentRequest.NumberOfSelectionEdits.ShippingAddress.Completed", 1)); + Assert.assertEquals(1, + RecordHistogram.getHistogramValueCountForTesting( + "PaymentRequest.NumberOfSelectionEdits.ShippingAddress.Completed", 1)); // Since the edit was not for the default selection a change should be logged. - assertEquals( - 1, RecordHistogram.getHistogramValueCountForTesting( - "PaymentRequest.NumberOfSelectionChanges.ShippingAddress.Completed", 1)); + Assert.assertEquals(1, + RecordHistogram.getHistogramValueCountForTesting( + "PaymentRequest.NumberOfSelectionChanges.ShippingAddress.Completed", 1)); // Make sure no add was logged. - assertEquals( - 1, RecordHistogram.getHistogramValueCountForTesting( - "PaymentRequest.NumberOfSelectionAdds.ShippingAddress.Completed", 0)); + Assert.assertEquals(1, + RecordHistogram.getHistogramValueCountForTesting( + "PaymentRequest.NumberOfSelectionAdds.ShippingAddress.Completed", 0)); } /** * Expect that the NumberOfSelectionAdds histogram gets logged properly for shipping addresses. */ + @Test @MediumTest @Feature({"Payments"}) public void testNumberOfSelectionAdds_ShippingAddress_Completed() throws InterruptedException, ExecutionException, TimeoutException { // Complete a Payment Request with a credit card. - triggerUIAndWait("ccBuy", getReadyToPay()); - clickInShippingSummaryAndWait(R.id.payments_section, getReadyForInput()); + mPaymentRequestTestRule.triggerUIAndWait("ccBuy", mPaymentRequestTestRule.getReadyToPay()); + mPaymentRequestTestRule.clickInShippingSummaryAndWait( + R.id.payments_section, mPaymentRequestTestRule.getReadyForInput()); // Add a new shipping address. - clickInShippingAddressAndWait(R.id.payments_add_option_button, getReadyToEdit()); - setSpinnerSelectionInEditorAndWait(0 /* Afghanistan */, getReadyToEdit()); - setTextInEditorAndWait(new String[] {"Alice", "Supreme Court", "Airport Road", "Kabul", - "1043", "650-253-0000"}, - getEditorTextUpdate()); - clickInEditorAndWait(R.id.payments_edit_done_button, getReadyToPay()); + mPaymentRequestTestRule.clickInShippingAddressAndWait( + R.id.payments_add_option_button, mPaymentRequestTestRule.getReadyToEdit()); + mPaymentRequestTestRule.setSpinnerSelectionInEditorAndWait( + 0 /* Afghanistan */, mPaymentRequestTestRule.getReadyToEdit()); + mPaymentRequestTestRule.setTextInEditorAndWait( + new String[] { + "Alice", "Supreme Court", "Airport Road", "Kabul", "1043", "650-253-0000"}, + mPaymentRequestTestRule.getEditorTextUpdate()); + mPaymentRequestTestRule.clickInEditorAndWait( + R.id.payments_edit_done_button, mPaymentRequestTestRule.getReadyToPay()); // Complete the transaction. - clickAndWait(R.id.button_primary, getReadyForUnmaskInput()); - setTextInCardUnmaskDialogAndWait(R.id.card_unmask_input, "123", getReadyToUnmask()); - clickCardUnmaskButtonAndWait(DialogInterface.BUTTON_POSITIVE, getDismissed()); + mPaymentRequestTestRule.clickAndWait( + R.id.button_primary, mPaymentRequestTestRule.getReadyForUnmaskInput()); + mPaymentRequestTestRule.setTextInCardUnmaskDialogAndWait( + R.id.card_unmask_input, "123", mPaymentRequestTestRule.getReadyToUnmask()); + mPaymentRequestTestRule.clickCardUnmaskButtonAndWait( + DialogInterface.BUTTON_POSITIVE, mPaymentRequestTestRule.getDismissed()); // Make sure the add was logged. - assertEquals( - 1, RecordHistogram.getHistogramValueCountForTesting( - "PaymentRequest.NumberOfSelectionAdds.ShippingAddress.Completed", 1)); + Assert.assertEquals(1, + RecordHistogram.getHistogramValueCountForTesting( + "PaymentRequest.NumberOfSelectionAdds.ShippingAddress.Completed", 1)); // Make sure no edits or changes were logged. - assertEquals( - 1, RecordHistogram.getHistogramValueCountForTesting( - "PaymentRequest.NumberOfSelectionChanges.ShippingAddress.Completed", 0)); - assertEquals( - 1, RecordHistogram.getHistogramValueCountForTesting( - "PaymentRequest.NumberOfSelectionEdits.ShippingAddress.Completed", 0)); + Assert.assertEquals(1, + RecordHistogram.getHistogramValueCountForTesting( + "PaymentRequest.NumberOfSelectionChanges.ShippingAddress.Completed", 0)); + Assert.assertEquals(1, + RecordHistogram.getHistogramValueCountForTesting( + "PaymentRequest.NumberOfSelectionEdits.ShippingAddress.Completed", 0)); } /** * Expect that the number of credit card suggestions was logged properly. */ + @Test @MediumTest @Feature({"Payments"}) public void testNumberOfSuggestionsShown_CreditCards_Completed() throws InterruptedException, ExecutionException, TimeoutException { // Complete a Payment Request with a credit card. - triggerUIAndWait("ccBuy", getReadyToPay()); - clickAndWait(R.id.button_primary, getReadyForUnmaskInput()); - setTextInCardUnmaskDialogAndWait(R.id.card_unmask_input, "123", getReadyToUnmask()); - clickCardUnmaskButtonAndWait(DialogInterface.BUTTON_POSITIVE, getDismissed()); + mPaymentRequestTestRule.triggerUIAndWait("ccBuy", mPaymentRequestTestRule.getReadyToPay()); + mPaymentRequestTestRule.clickAndWait( + R.id.button_primary, mPaymentRequestTestRule.getReadyForUnmaskInput()); + mPaymentRequestTestRule.setTextInCardUnmaskDialogAndWait( + R.id.card_unmask_input, "123", mPaymentRequestTestRule.getReadyToUnmask()); + mPaymentRequestTestRule.clickCardUnmaskButtonAndWait( + DialogInterface.BUTTON_POSITIVE, mPaymentRequestTestRule.getDismissed()); // Make sure the right number of suggestions were logged. - assertEquals( - 1, RecordHistogram.getHistogramValueCountForTesting( - "PaymentRequest.NumberOfSuggestionsShown.CreditCards.Completed", 2)); + Assert.assertEquals(1, + RecordHistogram.getHistogramValueCountForTesting( + "PaymentRequest.NumberOfSuggestionsShown.CreditCards.Completed", 2)); // Make sure no adds, edits or changes were logged. - assertEquals(1, RecordHistogram.getHistogramValueCountForTesting( - "PaymentRequest.NumberOfSelectionAdds.CreditCards.Completed", 0)); - assertEquals( - 1, RecordHistogram.getHistogramValueCountForTesting( - "PaymentRequest.NumberOfSelectionChanges.CreditCards.Completed", 0)); - assertEquals(1, RecordHistogram.getHistogramValueCountForTesting( - "PaymentRequest.NumberOfSelectionEdits.CreditCards.Completed", 0)); + Assert.assertEquals(1, + RecordHistogram.getHistogramValueCountForTesting( + "PaymentRequest.NumberOfSelectionAdds.CreditCards.Completed", 0)); + Assert.assertEquals(1, + RecordHistogram.getHistogramValueCountForTesting( + "PaymentRequest.NumberOfSelectionChanges.CreditCards.Completed", 0)); + Assert.assertEquals(1, + RecordHistogram.getHistogramValueCountForTesting( + "PaymentRequest.NumberOfSelectionEdits.CreditCards.Completed", 0)); } /** * Expect that the number of credit card suggestions was logged properly. */ + @Test @MediumTest @Feature({"Payments"}) public void testNumberOfSuggestionsShown_CreditCards_AbortedByUser() throws InterruptedException, ExecutionException, TimeoutException { // Cancel the payment request. - triggerUIAndWait("ccBuy", getReadyToPay()); - clickAndWait(R.id.close_button, getDismissed()); + mPaymentRequestTestRule.triggerUIAndWait("ccBuy", mPaymentRequestTestRule.getReadyToPay()); + mPaymentRequestTestRule.clickAndWait( + R.id.close_button, mPaymentRequestTestRule.getDismissed()); // Wait for the histograms to be logged. Thread.sleep(200); // Make sure the right number of suggestions were logged. - assertEquals( - 1, RecordHistogram.getHistogramValueCountForTesting( - "PaymentRequest.NumberOfSuggestionsShown.CreditCards.UserAborted", 2)); + Assert.assertEquals(1, + RecordHistogram.getHistogramValueCountForTesting( + "PaymentRequest.NumberOfSuggestionsShown.CreditCards.UserAborted", 2)); // Make sure no adds, edits or changes were logged. - assertEquals(1, RecordHistogram.getHistogramValueCountForTesting( - "PaymentRequest.NumberOfSelectionAdds.CreditCards.UserAborted", 0)); - assertEquals( - 1, RecordHistogram.getHistogramValueCountForTesting( - "PaymentRequest.NumberOfSelectionChanges.CreditCards.UserAborted", 0)); - assertEquals( - 1, RecordHistogram.getHistogramValueCountForTesting( - "PaymentRequest.NumberOfSelectionEdits.CreditCards.UserAborted", 0)); + Assert.assertEquals(1, + RecordHistogram.getHistogramValueCountForTesting( + "PaymentRequest.NumberOfSelectionAdds.CreditCards.UserAborted", 0)); + Assert.assertEquals(1, + RecordHistogram.getHistogramValueCountForTesting( + "PaymentRequest.NumberOfSelectionChanges.CreditCards.UserAborted", 0)); + Assert.assertEquals(1, + RecordHistogram.getHistogramValueCountForTesting( + "PaymentRequest.NumberOfSelectionEdits.CreditCards.UserAborted", 0)); } /** * Expect that the NumberOfSelectionAdds histogram gets logged properly for credit cards. */ + @Test @MediumTest @Feature({"Payments"}) public void testNumberOfSelectionAdds_CreditCards_Completed() throws InterruptedException, ExecutionException, TimeoutException { // Complete a Payment Request with a credit card. - triggerUIAndWait("ccBuy", getReadyToPay()); + mPaymentRequestTestRule.triggerUIAndWait("ccBuy", mPaymentRequestTestRule.getReadyToPay()); // Add a new credit card. - clickInPaymentMethodAndWait(R.id.payments_section, getReadyForInput()); - clickInPaymentMethodAndWait(R.id.payments_add_option_button, getReadyToEdit()); - setSpinnerSelectionsInCardEditorAndWait( - new int[] {11, 1, 0}, getBillingAddressChangeProcessed()); - setTextInCardEditorAndWait( - new String[] {"4111111111111111", "Jon Doe"}, getEditorTextUpdate()); - clickInCardEditorAndWait(R.id.payments_edit_done_button, getReadyToPay()); + mPaymentRequestTestRule.clickInPaymentMethodAndWait( + R.id.payments_section, mPaymentRequestTestRule.getReadyForInput()); + mPaymentRequestTestRule.clickInPaymentMethodAndWait( + R.id.payments_add_option_button, mPaymentRequestTestRule.getReadyToEdit()); + mPaymentRequestTestRule.setSpinnerSelectionsInCardEditorAndWait( + new int[] {11, 1, 0}, mPaymentRequestTestRule.getBillingAddressChangeProcessed()); + mPaymentRequestTestRule.setTextInCardEditorAndWait( + new String[] {"4111111111111111", "Jon Doe"}, + mPaymentRequestTestRule.getEditorTextUpdate()); + mPaymentRequestTestRule.clickInCardEditorAndWait( + R.id.payments_edit_done_button, mPaymentRequestTestRule.getReadyToPay()); // Complete the transaction. - clickAndWait(R.id.button_primary, getReadyForUnmaskInput()); - setTextInCardUnmaskDialogAndWait(R.id.card_unmask_input, "123", getReadyToUnmask()); - clickCardUnmaskButtonAndWait(DialogInterface.BUTTON_POSITIVE, getDismissed()); + mPaymentRequestTestRule.clickAndWait( + R.id.button_primary, mPaymentRequestTestRule.getReadyForUnmaskInput()); + mPaymentRequestTestRule.setTextInCardUnmaskDialogAndWait( + R.id.card_unmask_input, "123", mPaymentRequestTestRule.getReadyToUnmask()); + mPaymentRequestTestRule.clickCardUnmaskButtonAndWait( + DialogInterface.BUTTON_POSITIVE, mPaymentRequestTestRule.getDismissed()); // Make sure the add was logged. - assertEquals(1, RecordHistogram.getHistogramValueCountForTesting( - "PaymentRequest.NumberOfSelectionAdds.CreditCards.Completed", 1)); + Assert.assertEquals(1, + RecordHistogram.getHistogramValueCountForTesting( + "PaymentRequest.NumberOfSelectionAdds.CreditCards.Completed", 1)); // Make sure no edits or changes were logged. - assertEquals( - 1, RecordHistogram.getHistogramValueCountForTesting( - "PaymentRequest.NumberOfSelectionChanges.CreditCards.Completed", 0)); - assertEquals(1, RecordHistogram.getHistogramValueCountForTesting( - "PaymentRequest.NumberOfSelectionEdits.CreditCards.Completed", 0)); + Assert.assertEquals(1, + RecordHistogram.getHistogramValueCountForTesting( + "PaymentRequest.NumberOfSelectionChanges.CreditCards.Completed", 0)); + Assert.assertEquals(1, + RecordHistogram.getHistogramValueCountForTesting( + "PaymentRequest.NumberOfSelectionEdits.CreditCards.Completed", 0)); } /** * Expect that no metric for contact info has been logged. */ + @Test @MediumTest @Feature({"Payments"}) public void testNoContactInfoHistogram() throws InterruptedException, ExecutionException, TimeoutException { // Complete a Payment Request with a credit card. - triggerUIAndWait("ccBuy", getReadyToPay()); - clickAndWait(R.id.button_primary, getReadyForUnmaskInput()); - setTextInCardUnmaskDialogAndWait(R.id.card_unmask_input, "123", getReadyToUnmask()); - clickCardUnmaskButtonAndWait(DialogInterface.BUTTON_POSITIVE, getDismissed()); + mPaymentRequestTestRule.triggerUIAndWait("ccBuy", mPaymentRequestTestRule.getReadyToPay()); + mPaymentRequestTestRule.clickAndWait( + R.id.button_primary, mPaymentRequestTestRule.getReadyForUnmaskInput()); + mPaymentRequestTestRule.setTextInCardUnmaskDialogAndWait( + R.id.card_unmask_input, "123", mPaymentRequestTestRule.getReadyToUnmask()); + mPaymentRequestTestRule.clickCardUnmaskButtonAndWait( + DialogInterface.BUTTON_POSITIVE, mPaymentRequestTestRule.getDismissed()); // Make sure nothing was logged for contact info. - assertEquals( - 0, RecordHistogram.getHistogramValueCountForTesting( - "PaymentRequest.NumberOfSuggestionsShown.ContactInfo.Completed", 2)); - assertEquals(0, RecordHistogram.getHistogramValueCountForTesting( - "PaymentRequest.NumberOfSelectionAdds.ContactInfo.Completed", 0)); - assertEquals( - 0, RecordHistogram.getHistogramValueCountForTesting( - "PaymentRequest.NumberOfSelectionChanges.ContactInfo.Completed", 0)); - assertEquals(0, RecordHistogram.getHistogramValueCountForTesting( - "PaymentRequest.NumberOfSelectionEdits.ContactInfo.Completed", 0)); + Assert.assertEquals(0, + RecordHistogram.getHistogramValueCountForTesting( + "PaymentRequest.NumberOfSuggestionsShown.ContactInfo.Completed", 2)); + Assert.assertEquals(0, + RecordHistogram.getHistogramValueCountForTesting( + "PaymentRequest.NumberOfSelectionAdds.ContactInfo.Completed", 0)); + Assert.assertEquals(0, + RecordHistogram.getHistogramValueCountForTesting( + "PaymentRequest.NumberOfSelectionChanges.ContactInfo.Completed", 0)); + Assert.assertEquals(0, + RecordHistogram.getHistogramValueCountForTesting( + "PaymentRequest.NumberOfSelectionEdits.ContactInfo.Completed", 0)); } /** * Expect that that the journey metrics are logged correctly on a second consecutive payment * request. */ + @Test @MediumTest @Feature({"Payments"}) public void testTwoTimes() throws InterruptedException, ExecutionException, TimeoutException { // Complete a Payment Request with a credit card. - triggerUIAndWait("ccBuy", getReadyToPay()); - clickAndWait(R.id.button_primary, getReadyForUnmaskInput()); - setTextInCardUnmaskDialogAndWait(R.id.card_unmask_input, "123", getReadyToUnmask()); - clickCardUnmaskButtonAndWait(DialogInterface.BUTTON_POSITIVE, getDismissed()); + mPaymentRequestTestRule.triggerUIAndWait("ccBuy", mPaymentRequestTestRule.getReadyToPay()); + mPaymentRequestTestRule.clickAndWait( + R.id.button_primary, mPaymentRequestTestRule.getReadyForUnmaskInput()); + mPaymentRequestTestRule.setTextInCardUnmaskDialogAndWait( + R.id.card_unmask_input, "123", mPaymentRequestTestRule.getReadyToUnmask()); + mPaymentRequestTestRule.clickCardUnmaskButtonAndWait( + DialogInterface.BUTTON_POSITIVE, mPaymentRequestTestRule.getDismissed()); // Make sure the right number of suggestions were logged. - assertEquals( - 1, RecordHistogram.getHistogramValueCountForTesting( - "PaymentRequest.NumberOfSuggestionsShown.ShippingAddress.Completed", 2)); + Assert.assertEquals(1, + RecordHistogram.getHistogramValueCountForTesting( + "PaymentRequest.NumberOfSuggestionsShown.ShippingAddress.Completed", 2)); // Make sure no adds, edits or changes were logged. - assertEquals( - 1, RecordHistogram.getHistogramValueCountForTesting( - "PaymentRequest.NumberOfSelectionAdds.ShippingAddress.Completed", 0)); - assertEquals( - 1, RecordHistogram.getHistogramValueCountForTesting( - "PaymentRequest.NumberOfSelectionChanges.ShippingAddress.Completed", 0)); - assertEquals( - 1, RecordHistogram.getHistogramValueCountForTesting( - "PaymentRequest.NumberOfSelectionEdits.ShippingAddress.Completed", 0)); + Assert.assertEquals(1, + RecordHistogram.getHistogramValueCountForTesting( + "PaymentRequest.NumberOfSelectionAdds.ShippingAddress.Completed", 0)); + Assert.assertEquals(1, + RecordHistogram.getHistogramValueCountForTesting( + "PaymentRequest.NumberOfSelectionChanges.ShippingAddress.Completed", 0)); + Assert.assertEquals(1, + RecordHistogram.getHistogramValueCountForTesting( + "PaymentRequest.NumberOfSelectionEdits.ShippingAddress.Completed", 0)); // Complete a second Payment Request with a credit card. - reTriggerUIAndWait("ccBuy", getReadyToPay()); - clickAndWait(R.id.button_primary, getReadyForUnmaskInput()); - setTextInCardUnmaskDialogAndWait(R.id.card_unmask_input, "123", getReadyToUnmask()); - clickCardUnmaskButtonAndWait(DialogInterface.BUTTON_POSITIVE, getDismissed()); + mPaymentRequestTestRule.reTriggerUIAndWait( + "ccBuy", mPaymentRequestTestRule.getReadyToPay()); + mPaymentRequestTestRule.clickAndWait( + R.id.button_primary, mPaymentRequestTestRule.getReadyForUnmaskInput()); + mPaymentRequestTestRule.setTextInCardUnmaskDialogAndWait( + R.id.card_unmask_input, "123", mPaymentRequestTestRule.getReadyToUnmask()); + mPaymentRequestTestRule.clickCardUnmaskButtonAndWait( + DialogInterface.BUTTON_POSITIVE, mPaymentRequestTestRule.getDismissed()); // Make sure the right number of suggestions were logged. - assertEquals( - 2, RecordHistogram.getHistogramValueCountForTesting( - "PaymentRequest.NumberOfSuggestionsShown.ShippingAddress.Completed", 2)); + Assert.assertEquals(2, + RecordHistogram.getHistogramValueCountForTesting( + "PaymentRequest.NumberOfSuggestionsShown.ShippingAddress.Completed", 2)); // Make sure no adds, edits or changes were logged. - assertEquals( - 2, RecordHistogram.getHistogramValueCountForTesting( - "PaymentRequest.NumberOfSelectionAdds.ShippingAddress.Completed", 0)); - assertEquals( - 2, RecordHistogram.getHistogramValueCountForTesting( - "PaymentRequest.NumberOfSelectionChanges.ShippingAddress.Completed", 0)); - assertEquals( - 2, RecordHistogram.getHistogramValueCountForTesting( - "PaymentRequest.NumberOfSelectionEdits.ShippingAddress.Completed", 0)); + Assert.assertEquals(2, + RecordHistogram.getHistogramValueCountForTesting( + "PaymentRequest.NumberOfSelectionAdds.ShippingAddress.Completed", 0)); + Assert.assertEquals(2, + RecordHistogram.getHistogramValueCountForTesting( + "PaymentRequest.NumberOfSelectionChanges.ShippingAddress.Completed", 0)); + Assert.assertEquals(2, + RecordHistogram.getHistogramValueCountForTesting( + "PaymentRequest.NumberOfSelectionEdits.ShippingAddress.Completed", 0)); } /** * Expect that no journey metrics are logged if the payment request was not shown to the user. */ + @Test @MediumTest @Feature({"Payments"}) public void testNoShow() throws InterruptedException, ExecutionException, TimeoutException { // Android Pay is supported but no instruments are present. - installPaymentApp("https://android.com/pay", NO_INSTRUMENTS, DELAYED_RESPONSE); - openPageAndClickNodeAndWait("androidPayBuy", getShowFailed()); - expectResultContains(new String[] {"The payment method is not supported"}); + mPaymentRequestTestRule.installPaymentApp( + "https://android.com/pay", NO_INSTRUMENTS, DELAYED_RESPONSE); + mPaymentRequestTestRule.openPageAndClickNodeAndWait( + "androidPayBuy", mPaymentRequestTestRule.getShowFailed()); + mPaymentRequestTestRule.expectResultContains( + new String[] {"The payment method is not supported"}); // Make sure that no journey metrics were logged. - assertEquals(0, + Assert.assertEquals(0, RecordHistogram.getHistogramValueCountForTesting( "PaymentRequest.NumberOfSuggestionsShown.ShippingAddress.UserAborted", 2)); - assertEquals(0, + Assert.assertEquals(0, RecordHistogram.getHistogramValueCountForTesting( "PaymentRequest.NumberOfSuggestionsShown.ShippingAddress.OtherAborted", 2)); - assertEquals( - 0, RecordHistogram.getHistogramValueCountForTesting( - "PaymentRequest.NumberOfSuggestionsShown.ShippingAddress.Completed", 2)); + Assert.assertEquals(0, + RecordHistogram.getHistogramValueCountForTesting( + "PaymentRequest.NumberOfSuggestionsShown.ShippingAddress.Completed", 2)); } }
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestMetricsTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestMetricsTest.java index 80a1d21..f413b85e 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestMetricsTest.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestMetricsTest.java
@@ -4,18 +4,33 @@ package org.chromium.chrome.browser.payments; +import static org.chromium.chrome.browser.payments.PaymentRequestTestRule.DELAYED_RESPONSE; +import static org.chromium.chrome.browser.payments.PaymentRequestTestRule.HAVE_INSTRUMENTS; +import static org.chromium.chrome.browser.payments.PaymentRequestTestRule.IMMEDIATE_RESPONSE; +import static org.chromium.chrome.browser.payments.PaymentRequestTestRule.NO_INSTRUMENTS; + import android.content.DialogInterface; +import android.support.test.InstrumentationRegistry; import android.support.test.filters.MediumTest; +import org.junit.Assert; +import org.junit.Rule; +import org.junit.Test; +import org.junit.runner.RunWith; + import org.chromium.base.ThreadUtils; import org.chromium.base.metrics.RecordHistogram; import org.chromium.base.test.util.CommandLineFlags; import org.chromium.base.test.util.Feature; import org.chromium.chrome.R; import org.chromium.chrome.browser.ChromeFeatureList; +import org.chromium.chrome.browser.ChromeSwitches; import org.chromium.chrome.browser.autofill.AutofillTestHelper; import org.chromium.chrome.browser.autofill.PersonalDataManager.AutofillProfile; import org.chromium.chrome.browser.autofill.PersonalDataManager.CreditCard; +import org.chromium.chrome.browser.payments.PaymentRequestTestRule.MainActivityStartCallback; +import org.chromium.chrome.test.ChromeActivityTestRule; +import org.chromium.chrome.test.ChromeJUnit4ClassRunner; import org.chromium.chrome.test.util.ChromeTabUtils; import java.util.concurrent.ExecutionException; @@ -24,10 +39,15 @@ /** * A payment integration test to validate the logging of Payment Request metrics. */ -public class PaymentRequestMetricsTest extends PaymentRequestTestBase { - public PaymentRequestMetricsTest() { - super("payment_request_metrics_test.html"); - } +@RunWith(ChromeJUnit4ClassRunner.class) +@CommandLineFlags.Add({ + ChromeSwitches.DISABLE_FIRST_RUN_EXPERIENCE, + ChromeActivityTestRule.DISABLE_NETWORK_PREDICTION_FLAG, +}) +public class PaymentRequestMetricsTest implements MainActivityStartCallback { + @Rule + public PaymentRequestTestRule mPaymentRequestTestRule = + new PaymentRequestTestRule("payment_request_metrics_test.html", this); @Override public void onMainActivityStarted() @@ -45,63 +65,74 @@ /** * Expect that the successful checkout funnel metrics are logged during a succesful checkout. */ + @Test @MediumTest @Feature({"Payments"}) - public void testSuccessCheckoutFunnel() throws InterruptedException, ExecutionException, - TimeoutException { + public void testSuccessCheckoutFunnel() + throws InterruptedException, ExecutionException, TimeoutException { // Initiate a payment request. - triggerUIAndWait("ccBuy", getReadyToPay()); + mPaymentRequestTestRule.triggerUIAndWait("ccBuy", mPaymentRequestTestRule.getReadyToPay()); // Make sure sure that the "Initiated" and "Shown" events were logged. - assertEquals(1, RecordHistogram.getHistogramValueCountForTesting( - "PaymentRequest.CheckoutFunnel.Initiated", 1)); - assertEquals(1, RecordHistogram.getHistogramValueCountForTesting( - "PaymentRequest.CheckoutFunnel.Shown", 1)); + Assert.assertEquals(1, + RecordHistogram.getHistogramValueCountForTesting( + "PaymentRequest.CheckoutFunnel.Initiated", 1)); + Assert.assertEquals(1, + RecordHistogram.getHistogramValueCountForTesting( + "PaymentRequest.CheckoutFunnel.Shown", 1)); // Click the pay button. - clickAndWait(R.id.button_primary, getReadyForUnmaskInput()); + mPaymentRequestTestRule.clickAndWait( + R.id.button_primary, mPaymentRequestTestRule.getReadyForUnmaskInput()); // Make sure sure that the "PayClicked" event was logged. - assertEquals(1, RecordHistogram.getHistogramValueCountForTesting( - "PaymentRequest.CheckoutFunnel.PayClicked", 1)); + Assert.assertEquals(1, + RecordHistogram.getHistogramValueCountForTesting( + "PaymentRequest.CheckoutFunnel.PayClicked", 1)); // Unmask the credit card, - setTextInCardUnmaskDialogAndWait(R.id.card_unmask_input, "123", getReadyToUnmask()); - clickCardUnmaskButtonAndWait(DialogInterface.BUTTON_POSITIVE, getDismissed()); + mPaymentRequestTestRule.setTextInCardUnmaskDialogAndWait( + R.id.card_unmask_input, "123", mPaymentRequestTestRule.getReadyToUnmask()); + mPaymentRequestTestRule.clickCardUnmaskButtonAndWait( + DialogInterface.BUTTON_POSITIVE, mPaymentRequestTestRule.getDismissed()); // Make sure sure that the "ReceivedInstrumentDetails" and "Completed" events were logged. - assertEquals(1, RecordHistogram.getHistogramValueCountForTesting( - "PaymentRequest.CheckoutFunnel.ReceivedInstrumentDetails", 1)); - assertEquals(1, RecordHistogram.getHistogramValueCountForTesting( - "PaymentRequest.CheckoutFunnel.Completed", 1)); + Assert.assertEquals(1, + RecordHistogram.getHistogramValueCountForTesting( + "PaymentRequest.CheckoutFunnel.ReceivedInstrumentDetails", 1)); + Assert.assertEquals(1, + RecordHistogram.getHistogramValueCountForTesting( + "PaymentRequest.CheckoutFunnel.Completed", 1)); } /** * Expect only the ABORT_REASON_ABORTED_BY_USER enum value gets logged when a user cancels a * Payment Request. */ + @Test @MediumTest @Feature({"Payments"}) - public void testAbortMetrics_AbortedByUser_CancelButton() throws InterruptedException, - ExecutionException, TimeoutException { - triggerUIAndWait("ccBuy", getReadyToPay()); - clickInShippingSummaryAndWait(R.id.payments_section, getReadyForInput()); + public void testAbortMetrics_AbortedByUser_CancelButton() + throws InterruptedException, ExecutionException, TimeoutException { + mPaymentRequestTestRule.triggerUIAndWait("ccBuy", mPaymentRequestTestRule.getReadyToPay()); + mPaymentRequestTestRule.clickInShippingSummaryAndWait( + R.id.payments_section, mPaymentRequestTestRule.getReadyForInput()); // Cancel the Payment Request. - int callCount = getDismissed().getCallCount(); + int callCount = mPaymentRequestTestRule.getDismissed().getCallCount(); ThreadUtils.runOnUiThreadBlocking(new Runnable() { @Override public void run() { - getPaymentRequestUI() + mPaymentRequestTestRule.getPaymentRequestUI() .getDialogForTest() .findViewById(R.id.button_secondary) .performClick(); } }); - getDismissed().waitForCallback(callCount); - expectResultContains(new String[] {"Request cancelled"}); + mPaymentRequestTestRule.getDismissed().waitForCallback(callCount); + mPaymentRequestTestRule.expectResultContains(new String[] {"Request cancelled"}); - assertOnlySpecificAbortMetricLogged( + mPaymentRequestTestRule.assertOnlySpecificAbortMetricLogged( PaymentRequestMetrics.ABORT_REASON_ABORTED_BY_USER); } @@ -109,18 +140,21 @@ * Expect only the ABORT_REASON_ABORTED_BY_USER enum value gets logged when a user presses on * the [X] button in the Payment Request dialog. */ + @Test @MediumTest @Feature({"Payments"}) - public void testAbortMetrics_AbortedByUser_XButton() throws InterruptedException, - ExecutionException, TimeoutException { - triggerUIAndWait("ccBuy", getReadyToPay()); - clickInShippingSummaryAndWait(R.id.payments_section, getReadyForInput()); + public void testAbortMetrics_AbortedByUser_XButton() + throws InterruptedException, ExecutionException, TimeoutException { + mPaymentRequestTestRule.triggerUIAndWait("ccBuy", mPaymentRequestTestRule.getReadyToPay()); + mPaymentRequestTestRule.clickInShippingSummaryAndWait( + R.id.payments_section, mPaymentRequestTestRule.getReadyForInput()); // Press the [X] button. - clickAndWait(R.id.close_button, getDismissed()); - expectResultContains(new String[] {"Request cancelled"}); + mPaymentRequestTestRule.clickAndWait( + R.id.close_button, mPaymentRequestTestRule.getDismissed()); + mPaymentRequestTestRule.expectResultContains(new String[] {"Request cancelled"}); - assertOnlySpecificAbortMetricLogged( + mPaymentRequestTestRule.assertOnlySpecificAbortMetricLogged( PaymentRequestMetrics.ABORT_REASON_ABORTED_BY_USER); } @@ -128,25 +162,27 @@ * Expect only the ABORT_REASON_ABORTED_BY_USER enum value gets logged when a user presses on * the back button on their phone during a Payment Request. */ + @Test @MediumTest @Feature({"Payments"}) - public void testAbortMetrics_AbortedByUser_BackButton() throws InterruptedException, - ExecutionException, TimeoutException { - triggerUIAndWait("ccBuy", getReadyToPay()); - clickInShippingSummaryAndWait(R.id.payments_section, getReadyForInput()); + public void testAbortMetrics_AbortedByUser_BackButton() + throws InterruptedException, ExecutionException, TimeoutException { + mPaymentRequestTestRule.triggerUIAndWait("ccBuy", mPaymentRequestTestRule.getReadyToPay()); + mPaymentRequestTestRule.clickInShippingSummaryAndWait( + R.id.payments_section, mPaymentRequestTestRule.getReadyForInput()); // Press the back button. - int callCount = getDismissed().getCallCount(); + int callCount = mPaymentRequestTestRule.getDismissed().getCallCount(); ThreadUtils.runOnUiThreadBlocking(new Runnable() { @Override public void run() { - getPaymentRequestUI().getDialogForTest().onBackPressed(); + mPaymentRequestTestRule.getPaymentRequestUI().getDialogForTest().onBackPressed(); } }); - getDismissed().waitForCallback(callCount); - expectResultContains(new String[] {"Request cancelled"}); + mPaymentRequestTestRule.getDismissed().waitForCallback(callCount); + mPaymentRequestTestRule.expectResultContains(new String[] {"Request cancelled"}); - assertOnlySpecificAbortMetricLogged( + mPaymentRequestTestRule.assertOnlySpecificAbortMetricLogged( PaymentRequestMetrics.ABORT_REASON_ABORTED_BY_USER); } @@ -154,17 +190,20 @@ * Expect only the ABORT_REASON_MOJO_RENDERER_CLOSING enum value gets logged when a user closes * the tab during a Payment Request. */ + @Test @MediumTest @Feature({"Payments"}) - public void testAbortMetrics_AbortedByUser_TabClosed() throws InterruptedException, - ExecutionException, TimeoutException { - triggerUIAndWait("ccBuy", getReadyToPay()); - clickInShippingSummaryAndWait(R.id.payments_section, getReadyForInput()); + public void testAbortMetrics_AbortedByUser_TabClosed() + throws InterruptedException, ExecutionException, TimeoutException { + mPaymentRequestTestRule.triggerUIAndWait("ccBuy", mPaymentRequestTestRule.getReadyToPay()); + mPaymentRequestTestRule.clickInShippingSummaryAndWait( + R.id.payments_section, mPaymentRequestTestRule.getReadyForInput()); // Press the back button. - ChromeTabUtils.closeCurrentTab(getInstrumentation(), getActivity()); + ChromeTabUtils.closeCurrentTab(InstrumentationRegistry.getInstrumentation(), + mPaymentRequestTestRule.getActivity()); - assertOnlySpecificAbortMetricLogged( + mPaymentRequestTestRule.assertOnlySpecificAbortMetricLogged( PaymentRequestMetrics.ABORT_REASON_MOJO_RENDERER_CLOSING); } @@ -172,17 +211,18 @@ * Expect only the ABORT_REASON_ABORTED_BY_MERCHANT enum value gets logged when a Payment * Request gets cancelled by the merchant. */ + @Test @MediumTest @Feature({"Payments"}) - public void testAbortMetrics_AbortedByMerchant() throws InterruptedException, - ExecutionException, TimeoutException { - triggerUIAndWait("ccBuy", getReadyToPay()); + public void testAbortMetrics_AbortedByMerchant() + throws InterruptedException, ExecutionException, TimeoutException { + mPaymentRequestTestRule.triggerUIAndWait("ccBuy", mPaymentRequestTestRule.getReadyToPay()); // Simulate an abort by the merchant. - clickNodeAndWait("abort", getDismissed()); - expectResultContains(new String[] {"Abort"}); + mPaymentRequestTestRule.clickNodeAndWait("abort", mPaymentRequestTestRule.getDismissed()); + mPaymentRequestTestRule.expectResultContains(new String[] {"Abort"}); - assertOnlySpecificAbortMetricLogged( + mPaymentRequestTestRule.assertOnlySpecificAbortMetricLogged( PaymentRequestMetrics.ABORT_REASON_ABORTED_BY_MERCHANT); } @@ -193,21 +233,26 @@ * not accept credit cards). It should instead be logged as a reason why the Payment Request was * not shown to the user. */ + @Test @MediumTest @Feature({"Payments"}) public void testMetrics_NoMatchingPaymentMethod() throws InterruptedException, ExecutionException, TimeoutException { // Android Pay is supported but no instruments are present. - installPaymentApp("https://android.com/pay", NO_INSTRUMENTS, DELAYED_RESPONSE); - openPageAndClickNodeAndWait("androidPayBuy", getShowFailed()); - expectResultContains(new String[] {"The payment method is not supported"}); + mPaymentRequestTestRule.installPaymentApp( + "https://android.com/pay", NO_INSTRUMENTS, DELAYED_RESPONSE); + mPaymentRequestTestRule.openPageAndClickNodeAndWait( + "androidPayBuy", mPaymentRequestTestRule.getShowFailed()); + mPaymentRequestTestRule.expectResultContains( + new String[] {"The payment method is not supported"}); // Make sure that it is not logged as an abort. - assertOnlySpecificAbortMetricLogged(-1 /* none */); + mPaymentRequestTestRule.assertOnlySpecificAbortMetricLogged(-1 /* none */); // Make sure that it was logged as a reason why the Payment Request was not shown. - assertEquals(1, RecordHistogram.getHistogramValueCountForTesting( - "PaymentRequest.CheckoutFunnel.NoShow", - PaymentRequestMetrics.NO_SHOW_NO_MATCHING_PAYMENT_METHOD)); + Assert.assertEquals(1, + RecordHistogram.getHistogramValueCountForTesting( + "PaymentRequest.CheckoutFunnel.NoShow", + PaymentRequestMetrics.NO_SHOW_NO_MATCHING_PAYMENT_METHOD)); } /** @@ -216,34 +261,42 @@ * merchant only accepts payment methods we don't support. It should instead be logged as a * reason why the Payment Request was not shown to the user. */ + @Test @MediumTest @Feature({"Payments"}) public void testMetrics_NoSupportedPaymentMethod() throws InterruptedException, ExecutionException, TimeoutException { - openPageAndClickNodeAndWait("noSupported", getShowFailed()); - expectResultContains(new String[] {"The payment method is not supported"}); + mPaymentRequestTestRule.openPageAndClickNodeAndWait( + "noSupported", mPaymentRequestTestRule.getShowFailed()); + mPaymentRequestTestRule.expectResultContains( + new String[] {"The payment method is not supported"}); // Make sure that it is not logged as an abort. - assertOnlySpecificAbortMetricLogged(-1 /* none */); + mPaymentRequestTestRule.assertOnlySpecificAbortMetricLogged(-1 /* none */); // Make sure that it was logged as a reason why the Payment Request was not shown. - assertEquals(1, RecordHistogram.getHistogramValueCountForTesting( - "PaymentRequest.CheckoutFunnel.NoShow", - PaymentRequestMetrics.NO_SHOW_NO_SUPPORTED_PAYMENT_METHOD)); + Assert.assertEquals(1, + RecordHistogram.getHistogramValueCountForTesting( + "PaymentRequest.CheckoutFunnel.NoShow", + PaymentRequestMetrics.NO_SHOW_NO_SUPPORTED_PAYMENT_METHOD)); } /** * Expect only the SELECTED_METHOD_CREDIT_CARD enum value to be logged for the * "SelectedPaymentMethod" histogram when completing a Payment Request with a credit card. */ + @Test @MediumTest @Feature({"Payments"}) - public void testSelectedPaymentMethod_CreditCard() throws InterruptedException, - ExecutionException, TimeoutException { + public void testSelectedPaymentMethod_CreditCard() + throws InterruptedException, ExecutionException, TimeoutException { // Complete a Payment Request with a credit card. - triggerUIAndWait("ccBuy", getReadyToPay()); - clickAndWait(R.id.button_primary, getReadyForUnmaskInput()); - setTextInCardUnmaskDialogAndWait(R.id.card_unmask_input, "123", getReadyToUnmask()); - clickCardUnmaskButtonAndWait(DialogInterface.BUTTON_POSITIVE, getDismissed()); + mPaymentRequestTestRule.triggerUIAndWait("ccBuy", mPaymentRequestTestRule.getReadyToPay()); + mPaymentRequestTestRule.clickAndWait( + R.id.button_primary, mPaymentRequestTestRule.getReadyForUnmaskInput()); + mPaymentRequestTestRule.setTextInCardUnmaskDialogAndWait( + R.id.card_unmask_input, "123", mPaymentRequestTestRule.getReadyToUnmask()); + mPaymentRequestTestRule.clickCardUnmaskButtonAndWait( + DialogInterface.BUTTON_POSITIVE, mPaymentRequestTestRule.getDismissed()); assertOnlySpecificSelectedPaymentMethodMetricLogged( PaymentRequestMetrics.SELECTED_METHOD_CREDIT_CARD); @@ -253,14 +306,18 @@ * Expect only the SELECTED_METHOD_ANDROID_PAY enum value to be logged for the * "SelectedPaymentMethod" histogram when completing a Payment Request with Android Pay. */ + @Test @MediumTest @Feature({"Payments"}) - public void testSelectedPaymentMethod_AndroidPay() throws InterruptedException, - ExecutionException, TimeoutException { + public void testSelectedPaymentMethod_AndroidPay() + throws InterruptedException, ExecutionException, TimeoutException { // Complete a Payment Request with Android Pay. - installPaymentApp("https://android.com/pay", HAVE_INSTRUMENTS, IMMEDIATE_RESPONSE); - triggerUIAndWait("androidPayBuy", getReadyToPay()); - clickAndWait(R.id.button_primary, getDismissed()); + mPaymentRequestTestRule.installPaymentApp( + "https://android.com/pay", HAVE_INSTRUMENTS, IMMEDIATE_RESPONSE); + mPaymentRequestTestRule.triggerUIAndWait( + "androidPayBuy", mPaymentRequestTestRule.getReadyToPay()); + mPaymentRequestTestRule.clickAndWait( + R.id.button_primary, mPaymentRequestTestRule.getDismissed()); assertOnlySpecificSelectedPaymentMethodMetricLogged( PaymentRequestMetrics.SELECTED_METHOD_ANDROID_PAY); @@ -270,18 +327,21 @@ * Expect that the SkippedShow metric is logged when the UI directly goes * to the payment app UI during a Payment Request. */ + @Test @MediumTest @Feature({"Payments"}) public void testMetrics_SkippedShow() throws InterruptedException, ExecutionException, TimeoutException { // Complete a Payment Request with Android Pay. - installPaymentApp("https://android.com/pay", HAVE_INSTRUMENTS, IMMEDIATE_RESPONSE); - triggerUIAndWait("androidPaySkipUiBuy", getResultReady()); + mPaymentRequestTestRule.installPaymentApp( + "https://android.com/pay", HAVE_INSTRUMENTS, IMMEDIATE_RESPONSE); + mPaymentRequestTestRule.triggerUIAndWait( + "androidPaySkipUiBuy", mPaymentRequestTestRule.getResultReady()); - assertEquals(1, + Assert.assertEquals(1, RecordHistogram.getHistogramValueCountForTesting( "PaymentRequest.CheckoutFunnel.SkippedShow", 1)); - assertEquals(0, + Assert.assertEquals(0, RecordHistogram.getHistogramValueCountForTesting( "PaymentRequest.CheckoutFunnel.Shown", 1)); } @@ -290,19 +350,22 @@ * Expect that the PaymentRequest UI is shown even if all the requirements are met to skip, if * the skip feature is disabled. */ + @Test @MediumTest @Feature({"Payments"}) @CommandLineFlags.Add({"disable-features=" + ChromeFeatureList.WEB_PAYMENTS_SINGLE_APP_UI_SKIP}) public void testMetrics_SkippedShow_Disabled() throws InterruptedException, ExecutionException, TimeoutException { // Complete a Payment Request with Android Pay. - installPaymentApp("https://android.com/pay", HAVE_INSTRUMENTS, IMMEDIATE_RESPONSE); - triggerUIAndWait("androidPaySkipUiBuy", getReadyToPay()); + mPaymentRequestTestRule.installPaymentApp( + "https://android.com/pay", HAVE_INSTRUMENTS, IMMEDIATE_RESPONSE); + mPaymentRequestTestRule.triggerUIAndWait( + "androidPaySkipUiBuy", mPaymentRequestTestRule.getReadyToPay()); - assertEquals(1, + Assert.assertEquals(1, RecordHistogram.getHistogramValueCountForTesting( "PaymentRequest.CheckoutFunnel.Shown", 1)); - assertEquals(0, + Assert.assertEquals(0, RecordHistogram.getHistogramValueCountForTesting( "PaymentRequest.CheckoutFunnel.SkippedShow", 1)); } @@ -310,28 +373,33 @@ /** * Expect that the "Shown" event is recorded only once. */ + @Test @MediumTest @Feature({"Payments"}) public void testShownLoggedOnlyOnce() throws InterruptedException, ExecutionException, TimeoutException { // Initiate a payment request. - triggerUIAndWait("ccBuy", getReadyToPay()); + mPaymentRequestTestRule.triggerUIAndWait("ccBuy", mPaymentRequestTestRule.getReadyToPay()); // Make sure sure that the "Shown" event was logged. - assertEquals(1, + Assert.assertEquals(1, RecordHistogram.getHistogramValueCountForTesting( "PaymentRequest.CheckoutFunnel.Shown", 1)); // Add a shipping address, which triggers a second "Show". - clickInShippingSummaryAndWait(R.id.payments_section, getReadyForInput()); - clickInShippingAddressAndWait(R.id.payments_add_option_button, getReadyToEdit()); - setTextInEditorAndWait(new String[] {"Seb Doe", "Google", "340 Main St", "Los Angeles", - "CA", "90291", "650-253-0000"}, - getEditorTextUpdate()); - clickInEditorAndWait(R.id.payments_edit_done_button, getReadyToPay()); + mPaymentRequestTestRule.clickInShippingSummaryAndWait( + R.id.payments_section, mPaymentRequestTestRule.getReadyForInput()); + mPaymentRequestTestRule.clickInShippingAddressAndWait( + R.id.payments_add_option_button, mPaymentRequestTestRule.getReadyToEdit()); + mPaymentRequestTestRule.setTextInEditorAndWait( + new String[] {"Seb Doe", "Google", "340 Main St", "Los Angeles", "CA", "90291", + "650-253-0000"}, + mPaymentRequestTestRule.getEditorTextUpdate()); + mPaymentRequestTestRule.clickInEditorAndWait( + R.id.payments_edit_done_button, mPaymentRequestTestRule.getReadyToPay()); // Make sure "Shown" is still logged only once. - assertEquals(1, + Assert.assertEquals(1, RecordHistogram.getHistogramValueCountForTesting( "PaymentRequest.CheckoutFunnel.Shown", 1)); } @@ -344,7 +412,7 @@ */ private void assertOnlySpecificSelectedPaymentMethodMetricLogged(int paymentMethod) { for (int i = 0; i < PaymentRequestMetrics.SELECTED_METHOD_MAX; ++i) { - assertEquals((i == paymentMethod ? 1 : 0), + Assert.assertEquals((i == paymentMethod ? 1 : 0), RecordHistogram.getHistogramValueCountForTesting( "PaymentRequest.SelectedPaymentMethod", i)); }
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestMultipleContactDetailsTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestMultipleContactDetailsTest.java index db3c743..9315d684 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestMultipleContactDetailsTest.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestMultipleContactDetailsTest.java
@@ -4,12 +4,25 @@ package org.chromium.chrome.browser.payments; +import static org.chromium.chrome.browser.payments.PaymentRequestTestRule.HAVE_INSTRUMENTS; +import static org.chromium.chrome.browser.payments.PaymentRequestTestRule.IMMEDIATE_RESPONSE; + import android.support.test.filters.MediumTest; +import org.junit.Assert; +import org.junit.Rule; +import org.junit.Test; +import org.junit.runner.RunWith; + +import org.chromium.base.test.util.CommandLineFlags; import org.chromium.base.test.util.Feature; import org.chromium.chrome.R; +import org.chromium.chrome.browser.ChromeSwitches; import org.chromium.chrome.browser.autofill.AutofillTestHelper; import org.chromium.chrome.browser.autofill.PersonalDataManager.AutofillProfile; +import org.chromium.chrome.browser.payments.PaymentRequestTestRule.MainActivityStartCallback; +import org.chromium.chrome.test.ChromeActivityTestRule; +import org.chromium.chrome.test.ChromeJUnit4ClassRunner; import java.util.ArrayList; import java.util.concurrent.ExecutionException; @@ -19,7 +32,16 @@ * A payment integration test for a merchant that requests contact details and a user that has * multiple contact detail options. */ -public class PaymentRequestMultipleContactDetailsTest extends PaymentRequestTestBase { +@RunWith(ChromeJUnit4ClassRunner.class) +@CommandLineFlags.Add({ + ChromeSwitches.DISABLE_FIRST_RUN_EXPERIENCE, + ChromeActivityTestRule.DISABLE_NETWORK_PREDICTION_FLAG, +}) +public class PaymentRequestMultipleContactDetailsTest implements MainActivityStartCallback { + @Rule + public PaymentRequestTestRule mPaymentRequestTestRule = + new PaymentRequestTestRule("payment_request_contact_details_test.html", this); + private static final AutofillProfile[] AUTOFILL_PROFILES = { // 0 - Incomplete (no phone) profile. new AutofillProfile("" /* guid */, "https://www.example.com" /* origin */, @@ -90,11 +112,6 @@ private int[] mCountsToSet; private int[] mDatesToSet; - public PaymentRequestMultipleContactDetailsTest() { - // The merchant requests a name, a phone number and an email address. - super("payment_request_contact_details_test.html"); - } - @Override public void onMainActivityStarted() throws InterruptedException, ExecutionException, TimeoutException { @@ -111,7 +128,7 @@ helper.setProfileUseStatsForTesting(guids.get(i), mCountsToSet[i], mDatesToSet[i]); } - installPaymentApp(HAVE_INSTRUMENTS, IMMEDIATE_RESPONSE); + mPaymentRequestTestRule.installPaymentApp(HAVE_INSTRUMENTS, IMMEDIATE_RESPONSE); } /** @@ -119,6 +136,7 @@ * are shown. They should be ordered by frecency and complete contact details should be * suggested first. */ + @Test @MediumTest @Feature({"Payments"}) public void testContactDetailsSuggestionOrdering() @@ -131,23 +149,25 @@ mCountsToSet = new int[] {20, 15, 10, 5, 1}; mDatesToSet = new int[] {5000, 5000, 5000, 5000, 1}; - triggerUIAndWait(getReadyForInput()); - clickInContactInfoAndWait(R.id.payments_section, getReadyForInput()); - assertEquals(4, getNumberOfContactDetailSuggestions()); - assertEquals("Lisa Simpson\n555 123-4567\nlisa@simpson.com", - getContactDetailsSuggestionLabel(0)); - assertEquals("Maggie Simpson\n555 123-4567\nmaggie@simpson.com", - getContactDetailsSuggestionLabel(1)); - assertEquals("Bart Simpson\nbart@simpson.com\nPhone number required", - getContactDetailsSuggestionLabel(2)); - assertEquals( - "Homer Simpson\n555 123-4567\nEmail required", getContactDetailsSuggestionLabel(3)); + mPaymentRequestTestRule.triggerUIAndWait(mPaymentRequestTestRule.getReadyForInput()); + mPaymentRequestTestRule.clickInContactInfoAndWait( + R.id.payments_section, mPaymentRequestTestRule.getReadyForInput()); + Assert.assertEquals(4, mPaymentRequestTestRule.getNumberOfContactDetailSuggestions()); + Assert.assertEquals("Lisa Simpson\n555 123-4567\nlisa@simpson.com", + mPaymentRequestTestRule.getContactDetailsSuggestionLabel(0)); + Assert.assertEquals("Maggie Simpson\n555 123-4567\nmaggie@simpson.com", + mPaymentRequestTestRule.getContactDetailsSuggestionLabel(1)); + Assert.assertEquals("Bart Simpson\nbart@simpson.com\nPhone number required", + mPaymentRequestTestRule.getContactDetailsSuggestionLabel(2)); + Assert.assertEquals("Homer Simpson\n555 123-4567\nEmail required", + mPaymentRequestTestRule.getContactDetailsSuggestionLabel(3)); } /** * Make sure the information required message has been displayed for incomplete contact details * correctly. */ + @Test @MediumTest @Feature({"Payments"}) public void testContactDetailsEditRequiredMessage() @@ -157,22 +177,24 @@ mCountsToSet = new int[] {15, 10, 5, 1}; mDatesToSet = new int[] {5000, 5000, 5000, 5000}; - triggerUIAndWait(getReadyForInput()); - clickInContactInfoAndWait(R.id.payments_section, getReadyForInput()); - assertEquals(4, getNumberOfContactDetailSuggestions()); - assertEquals("Bart Simpson\nbart@simpson.com\nPhone number required", - getContactDetailsSuggestionLabel(0)); - assertEquals( - "Homer Simpson\n555 123-4567\nEmail required", getContactDetailsSuggestionLabel(1)); - assertEquals("555 123-4567\nmarge@simpson.com\nName required", - getContactDetailsSuggestionLabel(2)); - assertEquals( - "Marge Simpson\nMore information required", getContactDetailsSuggestionLabel(3)); + mPaymentRequestTestRule.triggerUIAndWait(mPaymentRequestTestRule.getReadyForInput()); + mPaymentRequestTestRule.clickInContactInfoAndWait( + R.id.payments_section, mPaymentRequestTestRule.getReadyForInput()); + Assert.assertEquals(4, mPaymentRequestTestRule.getNumberOfContactDetailSuggestions()); + Assert.assertEquals("Bart Simpson\nbart@simpson.com\nPhone number required", + mPaymentRequestTestRule.getContactDetailsSuggestionLabel(0)); + Assert.assertEquals("Homer Simpson\n555 123-4567\nEmail required", + mPaymentRequestTestRule.getContactDetailsSuggestionLabel(1)); + Assert.assertEquals("555 123-4567\nmarge@simpson.com\nName required", + mPaymentRequestTestRule.getContactDetailsSuggestionLabel(2)); + Assert.assertEquals("Marge Simpson\nMore information required", + mPaymentRequestTestRule.getContactDetailsSuggestionLabel(3)); } /** * Makes sure that suggestions that are subsets of other fields (empty values) are deduped. */ + @Test @MediumTest @Feature({"Payments"}) public void testContactDetailsDedupe_EmptyFields() @@ -187,19 +209,21 @@ mCountsToSet = new int[] {1, 20, 15, 10, 5}; mDatesToSet = new int[] {1000, 4000, 3000, 2000, 1000}; - triggerUIAndWait(getReadyForInput()); - clickInContactInfoAndWait(R.id.payments_section, getReadyForInput()); + mPaymentRequestTestRule.triggerUIAndWait(mPaymentRequestTestRule.getReadyForInput()); + mPaymentRequestTestRule.clickInContactInfoAndWait( + R.id.payments_section, mPaymentRequestTestRule.getReadyForInput()); // Only the original profile with all the fields should be suggested. - assertEquals(1, getNumberOfContactDetailSuggestions()); - assertEquals("Lisa Simpson\n555 123-4567\nlisa@simpson.com", - getContactDetailsSuggestionLabel(0)); + Assert.assertEquals(1, mPaymentRequestTestRule.getNumberOfContactDetailSuggestions()); + Assert.assertEquals("Lisa Simpson\n555 123-4567\nlisa@simpson.com", + mPaymentRequestTestRule.getContactDetailsSuggestionLabel(0)); } /** * Makes sure that suggestions where some fields values are equal but with different case are * deduped. */ + @Test @MediumTest @Feature({"Payments"}) public void testContactDetailsDedupe_Capitalization() @@ -210,17 +234,19 @@ mCountsToSet = new int[] {15, 5}; mDatesToSet = new int[] {5000, 2000}; - triggerUIAndWait(getReadyForInput()); - clickInContactInfoAndWait(R.id.payments_section, getReadyForInput()); - assertEquals(1, getNumberOfContactDetailSuggestions()); - assertEquals("Lisa Simpson\n555 123-4567\nlisa@simpson.com", - getContactDetailsSuggestionLabel(0)); + mPaymentRequestTestRule.triggerUIAndWait(mPaymentRequestTestRule.getReadyForInput()); + mPaymentRequestTestRule.clickInContactInfoAndWait( + R.id.payments_section, mPaymentRequestTestRule.getReadyForInput()); + Assert.assertEquals(1, mPaymentRequestTestRule.getNumberOfContactDetailSuggestions()); + Assert.assertEquals("Lisa Simpson\n555 123-4567\nlisa@simpson.com", + mPaymentRequestTestRule.getContactDetailsSuggestionLabel(0)); } /** * Makes sure that suggestions where some fields values are subsets of the other are not * deduped. */ + @Test @MediumTest @Feature({"Payments"}) public void testContactDetailsDontDedupe_FieldSubset() @@ -232,12 +258,13 @@ mCountsToSet = new int[] {15, 25}; mDatesToSet = new int[] {5000, 7000}; - triggerUIAndWait(getReadyForInput()); - clickInContactInfoAndWait(R.id.payments_section, getReadyForInput()); - assertEquals(2, getNumberOfContactDetailSuggestions()); - assertEquals("Lisa Simpson\n555 123-4567\nfakelisa@simpson.com", - getContactDetailsSuggestionLabel(0)); - assertEquals("Lisa Simpson\n555 123-4567\nlisa@simpson.com", - getContactDetailsSuggestionLabel(1)); + mPaymentRequestTestRule.triggerUIAndWait(mPaymentRequestTestRule.getReadyForInput()); + mPaymentRequestTestRule.clickInContactInfoAndWait( + R.id.payments_section, mPaymentRequestTestRule.getReadyForInput()); + Assert.assertEquals(2, mPaymentRequestTestRule.getNumberOfContactDetailSuggestions()); + Assert.assertEquals("Lisa Simpson\n555 123-4567\nfakelisa@simpson.com", + mPaymentRequestTestRule.getContactDetailsSuggestionLabel(0)); + Assert.assertEquals("Lisa Simpson\n555 123-4567\nlisa@simpson.com", + mPaymentRequestTestRule.getContactDetailsSuggestionLabel(1)); } }
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestNameAndFreeShippingTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestNameAndFreeShippingTest.java index e36b025c..7917fba5 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestNameAndFreeShippingTest.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestNameAndFreeShippingTest.java
@@ -7,12 +7,22 @@ import android.content.DialogInterface; import android.support.test.filters.MediumTest; +import org.junit.Assert; +import org.junit.Rule; +import org.junit.Test; +import org.junit.runner.RunWith; + import org.chromium.base.metrics.RecordHistogram; +import org.chromium.base.test.util.CommandLineFlags; import org.chromium.base.test.util.Feature; import org.chromium.chrome.R; +import org.chromium.chrome.browser.ChromeSwitches; import org.chromium.chrome.browser.autofill.AutofillTestHelper; import org.chromium.chrome.browser.autofill.PersonalDataManager.AutofillProfile; import org.chromium.chrome.browser.autofill.PersonalDataManager.CreditCard; +import org.chromium.chrome.browser.payments.PaymentRequestTestRule.MainActivityStartCallback; +import org.chromium.chrome.test.ChromeActivityTestRule; +import org.chromium.chrome.test.ChromeJUnit4ClassRunner; import java.util.concurrent.ExecutionException; import java.util.concurrent.TimeoutException; @@ -21,11 +31,15 @@ * A payment integration test for a merchant that requests a payer name and provides free shipping * regardless of address. */ -public class PaymentRequestNameAndFreeShippingTest extends PaymentRequestTestBase { - public PaymentRequestNameAndFreeShippingTest() { - // This merchant requests a payer name and provides free shipping worldwide. - super("payment_request_name_and_free_shipping_test.html"); - } +@RunWith(ChromeJUnit4ClassRunner.class) +@CommandLineFlags.Add({ + ChromeSwitches.DISABLE_FIRST_RUN_EXPERIENCE, + ChromeActivityTestRule.DISABLE_NETWORK_PREDICTION_FLAG, +}) +public class PaymentRequestNameAndFreeShippingTest implements MainActivityStartCallback { + @Rule + public PaymentRequestTestRule mPaymentRequestTestRule = + new PaymentRequestTestRule("payment_request_name_and_free_shipping_test.html", this); @Override public void onMainActivityStarted() @@ -41,16 +55,20 @@ } /** Submit the payer name and shipping address to the merchant when the user clicks "Pay." */ + @Test @MediumTest @Feature({"Payments"}) public void testPay() throws InterruptedException, ExecutionException, TimeoutException { - triggerUIAndWait(getReadyToPay()); - clickAndWait(R.id.button_primary, getReadyForUnmaskInput()); - setTextInCardUnmaskDialogAndWait(R.id.card_unmask_input, "123", getReadyToUnmask()); - clickCardUnmaskButtonAndWait(DialogInterface.BUTTON_POSITIVE, getDismissed()); - expectResultContains(new String[] {"Jon Doe", "Jon Doe", "4111111111111111", "12", - "2050", "visa", "123", "Google", "340 Main St", "CA", "Los Angeles", "90291", "US", - "en", "freeShippingOption"}); + mPaymentRequestTestRule.triggerUIAndWait(mPaymentRequestTestRule.getReadyToPay()); + mPaymentRequestTestRule.clickAndWait( + R.id.button_primary, mPaymentRequestTestRule.getReadyForUnmaskInput()); + mPaymentRequestTestRule.setTextInCardUnmaskDialogAndWait( + R.id.card_unmask_input, "123", mPaymentRequestTestRule.getReadyToUnmask()); + mPaymentRequestTestRule.clickCardUnmaskButtonAndWait( + DialogInterface.BUTTON_POSITIVE, mPaymentRequestTestRule.getDismissed()); + mPaymentRequestTestRule.expectResultContains(new String[] {"Jon Doe", "Jon Doe", + "4111111111111111", "12", "2050", "visa", "123", "Google", "340 Main St", "CA", + "Los Angeles", "90291", "US", "en", "freeShippingOption"}); } /** @@ -58,17 +76,23 @@ * results in the appropriate metric being logged in the PaymentRequest.RequestedInformation * histogram. */ + @Test @MediumTest @Feature({"Payments"}) - public void testRequestedInformationMetric() throws InterruptedException, ExecutionException, - TimeoutException { + public void testRequestedInformationMetric() + throws InterruptedException, ExecutionException, TimeoutException { // Start the Payment Request. - triggerUIAndWait(getReadyToPay()); + mPaymentRequestTestRule.triggerUIAndWait(mPaymentRequestTestRule.getReadyToPay()); // Make sure that only the appropriate enum value was logged. for (int i = 0; i < PaymentRequestMetrics.REQUESTED_INFORMATION_MAX; ++i) { - assertEquals((i == (PaymentRequestMetrics.REQUESTED_INFORMATION_SHIPPING - | PaymentRequestMetrics.REQUESTED_INFORMATION_NAME) ? 1 : 0), + Assert.assertEquals( + (i + == (PaymentRequestMetrics.REQUESTED_INFORMATION_SHIPPING + | PaymentRequestMetrics + .REQUESTED_INFORMATION_NAME) + ? 1 + : 0), RecordHistogram.getHistogramValueCountForTesting( "PaymentRequest.RequestedInformation", i)); }
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestNameTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestNameTest.java index bb731fe0..e653ece 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestNameTest.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestNameTest.java
@@ -7,12 +7,22 @@ import android.content.DialogInterface; import android.support.test.filters.MediumTest; +import org.junit.Assert; +import org.junit.Rule; +import org.junit.Test; +import org.junit.runner.RunWith; + import org.chromium.base.metrics.RecordHistogram; +import org.chromium.base.test.util.CommandLineFlags; import org.chromium.base.test.util.Feature; import org.chromium.chrome.R; +import org.chromium.chrome.browser.ChromeSwitches; import org.chromium.chrome.browser.autofill.AutofillTestHelper; import org.chromium.chrome.browser.autofill.PersonalDataManager.AutofillProfile; import org.chromium.chrome.browser.autofill.PersonalDataManager.CreditCard; +import org.chromium.chrome.browser.payments.PaymentRequestTestRule.MainActivityStartCallback; +import org.chromium.chrome.test.ChromeActivityTestRule; +import org.chromium.chrome.test.ChromeJUnit4ClassRunner; import java.util.concurrent.ExecutionException; import java.util.concurrent.TimeoutException; @@ -20,11 +30,15 @@ /** * A payment integration test for a merchant that requests payer name. */ -public class PaymentRequestNameTest extends PaymentRequestTestBase { - public PaymentRequestNameTest() { - // This merchant request a payer name. - super("payment_request_name_test.html"); - } +@RunWith(ChromeJUnit4ClassRunner.class) +@CommandLineFlags.Add({ + ChromeSwitches.DISABLE_FIRST_RUN_EXPERIENCE, + ChromeActivityTestRule.DISABLE_NETWORK_PREDICTION_FLAG, +}) +public class PaymentRequestNameTest implements MainActivityStartCallback { + @Rule + public PaymentRequestTestRule mPaymentRequestTestRule = + new PaymentRequestTestRule("payment_request_name_test.html", this); @Override public void onMainActivityStarted() @@ -60,74 +74,96 @@ } /** Provide the existing valid payer name to the merchant. */ + @Test @MediumTest @Feature({"Payments"}) public void testPay() throws InterruptedException, ExecutionException, TimeoutException { - triggerUIAndWait(getReadyToPay()); - clickAndWait(R.id.button_primary, getReadyForUnmaskInput()); - setTextInCardUnmaskDialogAndWait(R.id.card_unmask_input, "123", getReadyToUnmask()); - clickCardUnmaskButtonAndWait(DialogInterface.BUTTON_POSITIVE, getDismissed()); - expectResultContains(new String[] {"Jon Doe"}); + mPaymentRequestTestRule.triggerUIAndWait(mPaymentRequestTestRule.getReadyToPay()); + mPaymentRequestTestRule.clickAndWait( + R.id.button_primary, mPaymentRequestTestRule.getReadyForUnmaskInput()); + mPaymentRequestTestRule.setTextInCardUnmaskDialogAndWait( + R.id.card_unmask_input, "123", mPaymentRequestTestRule.getReadyToUnmask()); + mPaymentRequestTestRule.clickCardUnmaskButtonAndWait( + DialogInterface.BUTTON_POSITIVE, mPaymentRequestTestRule.getDismissed()); + mPaymentRequestTestRule.expectResultContains(new String[] {"Jon Doe"}); } /** Attempt to add an invalid payer name and cancel the transaction. */ + @Test @MediumTest @Feature({"Payments"}) public void testAddInvalidNameAndCancel() throws InterruptedException, ExecutionException, TimeoutException { - triggerUIAndWait(getReadyToPay()); - clickInContactInfoAndWait(R.id.payments_section, getReadyForInput()); - clickInContactInfoAndWait(R.id.payments_add_option_button, getReadyToEdit()); - setTextInEditorAndWait(new String[] {""}, getEditorTextUpdate()); - clickInEditorAndWait(R.id.payments_edit_done_button, getEditorValidationError()); - clickInEditorAndWait(R.id.payments_edit_cancel_button, getReadyToPay()); - clickAndWait(R.id.close_button, getDismissed()); - expectResultContains(new String[] {"Request cancelled"}); + mPaymentRequestTestRule.triggerUIAndWait(mPaymentRequestTestRule.getReadyToPay()); + mPaymentRequestTestRule.clickInContactInfoAndWait( + R.id.payments_section, mPaymentRequestTestRule.getReadyForInput()); + mPaymentRequestTestRule.clickInContactInfoAndWait( + R.id.payments_add_option_button, mPaymentRequestTestRule.getReadyToEdit()); + mPaymentRequestTestRule.setTextInEditorAndWait( + new String[] {""}, mPaymentRequestTestRule.getEditorTextUpdate()); + mPaymentRequestTestRule.clickInEditorAndWait( + R.id.payments_edit_done_button, mPaymentRequestTestRule.getEditorValidationError()); + mPaymentRequestTestRule.clickInEditorAndWait( + R.id.payments_edit_cancel_button, mPaymentRequestTestRule.getReadyToPay()); + mPaymentRequestTestRule.clickAndWait( + R.id.close_button, mPaymentRequestTestRule.getDismissed()); + mPaymentRequestTestRule.expectResultContains(new String[] {"Request cancelled"}); } /** Add a new payer name and provide that to the merchant. */ + @Test @MediumTest @Feature({"Payments"}) public void testAddNameAndPay() throws InterruptedException, ExecutionException, TimeoutException { - triggerUIAndWait(getReadyToPay()); - clickInContactInfoAndWait(R.id.payments_section, getReadyForInput()); - clickInContactInfoAndWait(R.id.payments_add_option_button, getReadyToEdit()); - setTextInEditorAndWait(new String[] {"Jane Jones"}, getEditorTextUpdate()); - clickInEditorAndWait(R.id.payments_edit_done_button, getReadyToPay()); - clickAndWait(R.id.button_primary, getReadyForUnmaskInput()); - setTextInCardUnmaskDialogAndWait(R.id.card_unmask_input, "123", getReadyToUnmask()); - clickCardUnmaskButtonAndWait(DialogInterface.BUTTON_POSITIVE, getDismissed()); - expectResultContains(new String[] {"Jane Jones"}); + mPaymentRequestTestRule.triggerUIAndWait(mPaymentRequestTestRule.getReadyToPay()); + mPaymentRequestTestRule.clickInContactInfoAndWait( + R.id.payments_section, mPaymentRequestTestRule.getReadyForInput()); + mPaymentRequestTestRule.clickInContactInfoAndWait( + R.id.payments_add_option_button, mPaymentRequestTestRule.getReadyToEdit()); + mPaymentRequestTestRule.setTextInEditorAndWait( + new String[] {"Jane Jones"}, mPaymentRequestTestRule.getEditorTextUpdate()); + mPaymentRequestTestRule.clickInEditorAndWait( + R.id.payments_edit_done_button, mPaymentRequestTestRule.getReadyToPay()); + mPaymentRequestTestRule.clickAndWait( + R.id.button_primary, mPaymentRequestTestRule.getReadyForUnmaskInput()); + mPaymentRequestTestRule.setTextInCardUnmaskDialogAndWait( + R.id.card_unmask_input, "123", mPaymentRequestTestRule.getReadyToUnmask()); + mPaymentRequestTestRule.clickCardUnmaskButtonAndWait( + DialogInterface.BUTTON_POSITIVE, mPaymentRequestTestRule.getDismissed()); + mPaymentRequestTestRule.expectResultContains(new String[] {"Jane Jones"}); } /** * Makes sure that suggestions that are equal to or subsets of other suggestions are not shown * to the user. */ + @Test @MediumTest @Feature({"Payments"}) public void testSuggestionsDeduped() throws InterruptedException, ExecutionException, TimeoutException { - triggerUIAndWait(getReadyToPay()); - clickInContactInfoAndWait(R.id.payments_section, getReadyForInput()); - assertEquals(1, getNumberOfContactDetailSuggestions()); + mPaymentRequestTestRule.triggerUIAndWait(mPaymentRequestTestRule.getReadyToPay()); + mPaymentRequestTestRule.clickInContactInfoAndWait( + R.id.payments_section, mPaymentRequestTestRule.getReadyForInput()); + Assert.assertEquals(1, mPaymentRequestTestRule.getNumberOfContactDetailSuggestions()); } /** * Test that starting a payment request that requires only the user's payer name results in * the appropriate metric being logged in the PaymentRequest.RequestedInformation histogram. */ + @Test @MediumTest @Feature({"Payments"}) - public void testRequestedInformationMetric() throws InterruptedException, ExecutionException, - TimeoutException { + public void testRequestedInformationMetric() + throws InterruptedException, ExecutionException, TimeoutException { // Start the Payment Request. - triggerUIAndWait(getReadyToPay()); + mPaymentRequestTestRule.triggerUIAndWait(mPaymentRequestTestRule.getReadyToPay()); // Make sure that only the appropriate enum value was logged. for (int i = 0; i < PaymentRequestMetrics.REQUESTED_INFORMATION_MAX; ++i) { - assertEquals((i == PaymentRequestMetrics.REQUESTED_INFORMATION_NAME ? 1 : 0), + Assert.assertEquals((i == PaymentRequestMetrics.REQUESTED_INFORMATION_NAME ? 1 : 0), RecordHistogram.getHistogramValueCountForTesting( "PaymentRequest.RequestedInformation", i)); }
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestNoShippingTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestNoShippingTest.java index 78d7e3f..486cd42f 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestNoShippingTest.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestNoShippingTest.java
@@ -4,18 +4,32 @@ package org.chromium.chrome.browser.payments; +import static org.chromium.chrome.browser.payments.PaymentRequestTestRule.DECEMBER; +import static org.chromium.chrome.browser.payments.PaymentRequestTestRule.FIRST_BILLING_ADDRESS; +import static org.chromium.chrome.browser.payments.PaymentRequestTestRule.NEXT_YEAR; + import android.content.DialogInterface; import android.os.Build; import android.support.test.filters.MediumTest; +import org.junit.Assert; +import org.junit.Rule; +import org.junit.Test; +import org.junit.runner.RunWith; + import org.chromium.base.ThreadUtils; import org.chromium.base.metrics.RecordHistogram; +import org.chromium.base.test.util.CommandLineFlags; import org.chromium.base.test.util.Feature; import org.chromium.base.test.util.MinAndroidSdkLevel; import org.chromium.chrome.R; +import org.chromium.chrome.browser.ChromeSwitches; import org.chromium.chrome.browser.autofill.AutofillTestHelper; import org.chromium.chrome.browser.autofill.PersonalDataManager.AutofillProfile; import org.chromium.chrome.browser.autofill.PersonalDataManager.CreditCard; +import org.chromium.chrome.browser.payments.PaymentRequestTestRule.MainActivityStartCallback; +import org.chromium.chrome.test.ChromeActivityTestRule; +import org.chromium.chrome.test.ChromeJUnit4ClassRunner; import java.util.concurrent.ExecutionException; import java.util.concurrent.TimeoutException; @@ -23,10 +37,15 @@ /** * A payment integration test for a merchant that does not require shipping address. */ -public class PaymentRequestNoShippingTest extends PaymentRequestTestBase { - public PaymentRequestNoShippingTest() { - super("payment_request_no_shipping_test.html"); - } +@RunWith(ChromeJUnit4ClassRunner.class) +@CommandLineFlags.Add({ + ChromeSwitches.DISABLE_FIRST_RUN_EXPERIENCE, + ChromeActivityTestRule.DISABLE_NETWORK_PREDICTION_FLAG, +}) +public class PaymentRequestNoShippingTest implements MainActivityStartCallback { + @Rule + public PaymentRequestTestRule mPaymentRequestTestRule = + new PaymentRequestTestRule("payment_request_no_shipping_test.html", this); @Override public void onMainActivityStarted() @@ -41,65 +60,84 @@ } /** Click [X] to cancel payment. */ + @Test @MediumTest @Feature({"Payments"}) - public void testCloseDialog() throws InterruptedException, ExecutionException, - TimeoutException { - triggerUIAndWait(getReadyForInput()); - clickAndWait(R.id.close_button, getDismissed()); - expectResultContains(new String[] {"Request cancelled"}); + public void testCloseDialog() + throws InterruptedException, ExecutionException, TimeoutException { + mPaymentRequestTestRule.triggerUIAndWait(mPaymentRequestTestRule.getReadyForInput()); + mPaymentRequestTestRule.clickAndWait( + R.id.close_button, mPaymentRequestTestRule.getDismissed()); + mPaymentRequestTestRule.expectResultContains(new String[] {"Request cancelled"}); } /** Click [EDIT] to expand the dialog, then click [X] to cancel payment. */ + @Test @MediumTest @Feature({"Payments"}) - public void testEditAndCloseDialog() throws InterruptedException, ExecutionException, - TimeoutException { - triggerUIAndWait(getReadyForInput()); - clickAndWait(R.id.button_secondary, getReadyForInput()); - clickAndWait(R.id.close_button, getDismissed()); - expectResultContains(new String[] {"Request cancelled"}); + public void testEditAndCloseDialog() + throws InterruptedException, ExecutionException, TimeoutException { + mPaymentRequestTestRule.triggerUIAndWait(mPaymentRequestTestRule.getReadyForInput()); + mPaymentRequestTestRule.clickAndWait( + R.id.button_secondary, mPaymentRequestTestRule.getReadyForInput()); + mPaymentRequestTestRule.clickAndWait( + R.id.close_button, mPaymentRequestTestRule.getDismissed()); + mPaymentRequestTestRule.expectResultContains(new String[] {"Request cancelled"}); } /** Click [EDIT] to expand the dialog, then click [CANCEL] to cancel payment. */ + @Test @MediumTest @Feature({"Payments"}) - public void testEditAndCancelDialog() throws InterruptedException, ExecutionException, - TimeoutException { - triggerUIAndWait(getReadyForInput()); - clickAndWait(R.id.button_secondary, getReadyForInput()); - clickAndWait(R.id.button_secondary, getDismissed()); - expectResultContains(new String[] {"Request cancelled"}); + public void testEditAndCancelDialog() + throws InterruptedException, ExecutionException, TimeoutException { + mPaymentRequestTestRule.triggerUIAndWait(mPaymentRequestTestRule.getReadyForInput()); + mPaymentRequestTestRule.clickAndWait( + R.id.button_secondary, mPaymentRequestTestRule.getReadyForInput()); + mPaymentRequestTestRule.clickAndWait( + R.id.button_secondary, mPaymentRequestTestRule.getDismissed()); + mPaymentRequestTestRule.expectResultContains(new String[] {"Request cancelled"}); } /** Click [PAY] and dismiss the card unmask dialog. */ + @Test @MediumTest @Feature({"Payments"}) public void testPay() throws InterruptedException, ExecutionException, TimeoutException { - triggerUIAndWait(getReadyToPay()); - clickAndWait(R.id.button_primary, getReadyForUnmaskInput()); - setTextInCardUnmaskDialogAndWait(R.id.card_unmask_input, "123", getReadyToUnmask()); - clickCardUnmaskButtonAndWait(DialogInterface.BUTTON_POSITIVE, getDismissed()); - expectResultContains(new String[] {"Jon Doe", "4111111111111111", "12", "2050", "visa", - "123"}); + mPaymentRequestTestRule.triggerUIAndWait(mPaymentRequestTestRule.getReadyToPay()); + mPaymentRequestTestRule.clickAndWait( + R.id.button_primary, mPaymentRequestTestRule.getReadyForUnmaskInput()); + mPaymentRequestTestRule.setTextInCardUnmaskDialogAndWait( + R.id.card_unmask_input, "123", mPaymentRequestTestRule.getReadyToUnmask()); + mPaymentRequestTestRule.clickCardUnmaskButtonAndWait( + DialogInterface.BUTTON_POSITIVE, mPaymentRequestTestRule.getDismissed()); + mPaymentRequestTestRule.expectResultContains( + new String[] {"Jon Doe", "4111111111111111", "12", "2050", "visa", "123"}); } /** Click [PAY], type in "123" into the CVC dialog, then submit the payment. */ + @Test @MediumTest @Feature({"Payments"}) public void testCancelUnmaskAndRetry() throws InterruptedException, ExecutionException, TimeoutException { - triggerUIAndWait(getReadyToPay()); - clickAndWait(R.id.button_primary, getReadyForUnmaskInput()); - clickCardUnmaskButtonAndWait(DialogInterface.BUTTON_NEGATIVE, getReadyToPay()); - clickAndWait(R.id.button_primary, getReadyForUnmaskInput()); - setTextInCardUnmaskDialogAndWait(R.id.card_unmask_input, "123", getReadyToUnmask()); - clickCardUnmaskButtonAndWait(DialogInterface.BUTTON_POSITIVE, getDismissed()); - expectResultContains(new String[] {"Jon Doe", "4111111111111111", "12", "2050", "visa", - "123"}); + mPaymentRequestTestRule.triggerUIAndWait(mPaymentRequestTestRule.getReadyToPay()); + mPaymentRequestTestRule.clickAndWait( + R.id.button_primary, mPaymentRequestTestRule.getReadyForUnmaskInput()); + mPaymentRequestTestRule.clickCardUnmaskButtonAndWait( + DialogInterface.BUTTON_NEGATIVE, mPaymentRequestTestRule.getReadyToPay()); + mPaymentRequestTestRule.clickAndWait( + R.id.button_primary, mPaymentRequestTestRule.getReadyForUnmaskInput()); + mPaymentRequestTestRule.setTextInCardUnmaskDialogAndWait( + R.id.card_unmask_input, "123", mPaymentRequestTestRule.getReadyToUnmask()); + mPaymentRequestTestRule.clickCardUnmaskButtonAndWait( + DialogInterface.BUTTON_POSITIVE, mPaymentRequestTestRule.getDismissed()); + mPaymentRequestTestRule.expectResultContains( + new String[] {"Jon Doe", "4111111111111111", "12", "2050", "visa", "123"}); } /** Attempt to add an invalid credit card number and cancel payment. */ + @Test @MediumTest @Feature({"Payments"}) public void testAddInvalidCardNumberAndCancel() @@ -107,39 +145,53 @@ // Attempting to add an invalid card and cancelling out of the flow will result in the user // still being ready to pay with the previously selected credit card. fillNewCardForm("123", "Bob", DECEMBER, NEXT_YEAR, FIRST_BILLING_ADDRESS); - clickInCardEditorAndWait(R.id.payments_edit_done_button, getEditorValidationError()); - clickInCardEditorAndWait(R.id.payments_edit_cancel_button, getReadyToPay()); - clickAndWait(R.id.close_button, getDismissed()); - expectResultContains(new String[] {"Request cancelled"}); + mPaymentRequestTestRule.clickInCardEditorAndWait( + R.id.payments_edit_done_button, mPaymentRequestTestRule.getEditorValidationError()); + mPaymentRequestTestRule.clickInCardEditorAndWait( + R.id.payments_edit_cancel_button, mPaymentRequestTestRule.getReadyToPay()); + mPaymentRequestTestRule.clickAndWait( + R.id.close_button, mPaymentRequestTestRule.getDismissed()); + mPaymentRequestTestRule.expectResultContains(new String[] {"Request cancelled"}); } /** Attempt to add a credit card with an empty name on card and cancel payment. */ + @Test @MediumTest @MinAndroidSdkLevel(Build.VERSION_CODES.LOLLIPOP) // crbug.com/678983 @Feature({"Payments"}) public void testAddEmptyNameOnCardAndCancel() throws InterruptedException, ExecutionException, TimeoutException { fillNewCardForm("5454-5454-5454-5454", "", DECEMBER, NEXT_YEAR, FIRST_BILLING_ADDRESS); - clickInCardEditorAndWait(R.id.payments_edit_done_button, getEditorValidationError()); - clickInCardEditorAndWait(R.id.payments_edit_cancel_button, getReadyForInput()); - clickAndWait(R.id.close_button, getDismissed()); - expectResultContains(new String[] {"Request cancelled"}); + mPaymentRequestTestRule.clickInCardEditorAndWait( + R.id.payments_edit_done_button, mPaymentRequestTestRule.getEditorValidationError()); + mPaymentRequestTestRule.clickInCardEditorAndWait( + R.id.payments_edit_cancel_button, mPaymentRequestTestRule.getReadyForInput()); + mPaymentRequestTestRule.clickAndWait( + R.id.close_button, mPaymentRequestTestRule.getDismissed()); + mPaymentRequestTestRule.expectResultContains(new String[] {"Request cancelled"}); } /** Save a new card on disk and pay. */ + @Test @MediumTest @Feature({"Payments"}) public void testSaveNewCardAndPay() throws InterruptedException, ExecutionException, TimeoutException { fillNewCardForm("5454-5454-5454-5454", "Bob", DECEMBER, NEXT_YEAR, FIRST_BILLING_ADDRESS); - clickInCardEditorAndWait(R.id.payments_edit_done_button, getReadyToPay()); - clickAndWait(R.id.button_primary, getReadyForUnmaskInput()); - setTextInCardUnmaskDialogAndWait(R.id.card_unmask_input, "123", getReadyToUnmask()); - clickCardUnmaskButtonAndWait(DialogInterface.BUTTON_POSITIVE, getDismissed()); - expectResultContains(new String[] {"5454545454545454", "12", "Bob"}); + mPaymentRequestTestRule.clickInCardEditorAndWait( + R.id.payments_edit_done_button, mPaymentRequestTestRule.getReadyToPay()); + mPaymentRequestTestRule.clickAndWait( + R.id.button_primary, mPaymentRequestTestRule.getReadyForUnmaskInput()); + mPaymentRequestTestRule.setTextInCardUnmaskDialogAndWait( + R.id.card_unmask_input, "123", mPaymentRequestTestRule.getReadyToUnmask()); + mPaymentRequestTestRule.clickCardUnmaskButtonAndWait( + DialogInterface.BUTTON_POSITIVE, mPaymentRequestTestRule.getDismissed()); + mPaymentRequestTestRule.expectResultContains( + new String[] {"5454545454545454", "12", "Bob"}); } /** Use a temporary credit card to complete payment. */ + @Test @MediumTest @Feature({"Payments"}) public void testAddTemporaryCardAndPay() @@ -147,250 +199,287 @@ fillNewCardForm("5454-5454-5454-5454", "Bob", DECEMBER, NEXT_YEAR, FIRST_BILLING_ADDRESS); // Uncheck the "Save this card on this device" checkbox, so the card is temporary. - selectCheckboxAndWait(R.id.payments_edit_checkbox, false, getReadyToEdit()); + mPaymentRequestTestRule.selectCheckboxAndWait( + R.id.payments_edit_checkbox, false, mPaymentRequestTestRule.getReadyToEdit()); - clickInCardEditorAndWait(R.id.payments_edit_done_button, getReadyToPay()); - clickAndWait(R.id.button_primary, getReadyForUnmaskInput()); - setTextInCardUnmaskDialogAndWait(R.id.card_unmask_input, "123", getReadyToUnmask()); - clickCardUnmaskButtonAndWait(DialogInterface.BUTTON_POSITIVE, getDismissed()); - expectResultContains(new String[] {"5454545454545454", "12", "Bob"}); + mPaymentRequestTestRule.clickInCardEditorAndWait( + R.id.payments_edit_done_button, mPaymentRequestTestRule.getReadyToPay()); + mPaymentRequestTestRule.clickAndWait( + R.id.button_primary, mPaymentRequestTestRule.getReadyForUnmaskInput()); + mPaymentRequestTestRule.setTextInCardUnmaskDialogAndWait( + R.id.card_unmask_input, "123", mPaymentRequestTestRule.getReadyToUnmask()); + mPaymentRequestTestRule.clickCardUnmaskButtonAndWait( + DialogInterface.BUTTON_POSITIVE, mPaymentRequestTestRule.getDismissed()); + mPaymentRequestTestRule.expectResultContains( + new String[] {"5454545454545454", "12", "Bob"}); } private void fillNewCardForm(String cardNumber, String nameOnCard, int month, int year, int billingAddress) throws InterruptedException, ExecutionException, TimeoutException { - triggerUIAndWait(getReadyToPay()); - clickInPaymentMethodAndWait(R.id.payments_section, getReadyForInput()); - clickInPaymentMethodAndWait(R.id.payments_add_option_button, getReadyToEdit()); - setTextInCardEditorAndWait(new String[] {cardNumber, nameOnCard}, getEditorTextUpdate()); - setSpinnerSelectionsInCardEditorAndWait( - new int[] {month, year, billingAddress}, getBillingAddressChangeProcessed()); + mPaymentRequestTestRule.triggerUIAndWait(mPaymentRequestTestRule.getReadyToPay()); + mPaymentRequestTestRule.clickInPaymentMethodAndWait( + R.id.payments_section, mPaymentRequestTestRule.getReadyForInput()); + mPaymentRequestTestRule.clickInPaymentMethodAndWait( + R.id.payments_add_option_button, mPaymentRequestTestRule.getReadyToEdit()); + mPaymentRequestTestRule.setTextInCardEditorAndWait(new String[] {cardNumber, nameOnCard}, + mPaymentRequestTestRule.getEditorTextUpdate()); + mPaymentRequestTestRule.setSpinnerSelectionsInCardEditorAndWait( + new int[] {month, year, billingAddress}, + mPaymentRequestTestRule.getBillingAddressChangeProcessed()); } /** Add a new card together with a new billing address and pay. */ + @Test @MediumTest @Feature({"Payments"}) public void testSaveNewCardAndNewBillingAddressAndPay() throws InterruptedException, ExecutionException, TimeoutException { - triggerUIAndWait(getReadyToPay()); - clickInPaymentMethodAndWait(R.id.payments_section, getReadyForInput()); - clickInPaymentMethodAndWait(R.id.payments_add_option_button, getReadyToEdit()); - setTextInCardEditorAndWait( - new String[] {"5454 5454 5454 5454", "Bob"}, getEditorTextUpdate()); + mPaymentRequestTestRule.triggerUIAndWait(mPaymentRequestTestRule.getReadyToPay()); + mPaymentRequestTestRule.clickInPaymentMethodAndWait( + R.id.payments_section, mPaymentRequestTestRule.getReadyForInput()); + mPaymentRequestTestRule.clickInPaymentMethodAndWait( + R.id.payments_add_option_button, mPaymentRequestTestRule.getReadyToEdit()); + mPaymentRequestTestRule.setTextInCardEditorAndWait( + new String[] {"5454 5454 5454 5454", "Bob"}, + mPaymentRequestTestRule.getEditorTextUpdate()); // Select December of next year for expiration and [Add address] in the billing address // dropdown. int addBillingAddress = 1; - setSpinnerSelectionsInCardEditorAndWait( - new int[] {DECEMBER, NEXT_YEAR, addBillingAddress}, getReadyToEdit()); + mPaymentRequestTestRule.setSpinnerSelectionsInCardEditorAndWait( + new int[] {DECEMBER, NEXT_YEAR, addBillingAddress}, + mPaymentRequestTestRule.getReadyToEdit()); - setTextInEditorAndWait(new String[] {"Bob", "Google", "1600 Amphitheatre Pkwy", - "Mountain View", "CA", "94043", "650-253-0000"}, - getEditorTextUpdate()); - clickInEditorAndWait(R.id.payments_edit_done_button, getReadyToEdit()); + mPaymentRequestTestRule.setTextInEditorAndWait( + new String[] {"Bob", "Google", "1600 Amphitheatre Pkwy", "Mountain View", "CA", + "94043", "650-253-0000"}, + mPaymentRequestTestRule.getEditorTextUpdate()); + mPaymentRequestTestRule.clickInEditorAndWait( + R.id.payments_edit_done_button, mPaymentRequestTestRule.getReadyToEdit()); - clickInCardEditorAndWait(R.id.payments_edit_done_button, getReadyToPay()); - clickAndWait(R.id.button_primary, getReadyForUnmaskInput()); - setTextInCardUnmaskDialogAndWait(R.id.card_unmask_input, "123", getReadyToUnmask()); - clickCardUnmaskButtonAndWait(DialogInterface.BUTTON_POSITIVE, getDismissed()); - expectResultContains(new String[] {"5454545454545454", "12", "Bob", "Google", - "1600 Amphitheatre Pkwy", "Mountain View", "CA", "94043", "+16502530000"}); + mPaymentRequestTestRule.clickInCardEditorAndWait( + R.id.payments_edit_done_button, mPaymentRequestTestRule.getReadyToPay()); + mPaymentRequestTestRule.clickAndWait( + R.id.button_primary, mPaymentRequestTestRule.getReadyForUnmaskInput()); + mPaymentRequestTestRule.setTextInCardUnmaskDialogAndWait( + R.id.card_unmask_input, "123", mPaymentRequestTestRule.getReadyToUnmask()); + mPaymentRequestTestRule.clickCardUnmaskButtonAndWait( + DialogInterface.BUTTON_POSITIVE, mPaymentRequestTestRule.getDismissed()); + mPaymentRequestTestRule.expectResultContains( + new String[] {"5454545454545454", "12", "Bob", "Google", "1600 Amphitheatre Pkwy", + "Mountain View", "CA", "94043", "+16502530000"}); } /** Quickly pressing on "add card" and then [X] should not crash. */ + @Test @MediumTest @Feature({"Payments"}) public void testQuickAddCardAndCloseShouldNotCrash() throws InterruptedException, ExecutionException, TimeoutException { - triggerUIAndWait(getReadyToPay()); - clickInPaymentMethodAndWait(R.id.payments_section, getReadyForInput()); + mPaymentRequestTestRule.triggerUIAndWait(mPaymentRequestTestRule.getReadyToPay()); + mPaymentRequestTestRule.clickInPaymentMethodAndWait( + R.id.payments_section, mPaymentRequestTestRule.getReadyForInput()); // Quickly press on "add card" and then [X]. - int callCount = getReadyToEdit().getCallCount(); + int callCount = mPaymentRequestTestRule.getReadyToEdit().getCallCount(); ThreadUtils.runOnUiThreadBlocking(new Runnable() { @Override public void run() { - getPaymentRequestUI() + mPaymentRequestTestRule.getPaymentRequestUI() .getPaymentMethodSectionForTest() .findViewById(R.id.payments_add_option_button) .performClick(); - getPaymentRequestUI() + mPaymentRequestTestRule.getPaymentRequestUI() .getDialogForTest() .findViewById(R.id.close_button) .performClick(); } }); - getReadyToEdit().waitForCallback(callCount); + mPaymentRequestTestRule.getReadyToEdit().waitForCallback(callCount); - clickInCardEditorAndWait(R.id.payments_edit_cancel_button, getReadyToPay()); - clickAndWait(R.id.close_button, getDismissed()); - expectResultContains(new String[] {"Request cancelled"}); + mPaymentRequestTestRule.clickInCardEditorAndWait( + R.id.payments_edit_cancel_button, mPaymentRequestTestRule.getReadyToPay()); + mPaymentRequestTestRule.clickAndWait( + R.id.close_button, mPaymentRequestTestRule.getDismissed()); + mPaymentRequestTestRule.expectResultContains(new String[] {"Request cancelled"}); } /** Quickly pressing on [X] and then "add card" should not crash. */ + @Test @MediumTest @Feature({"Payments"}) public void testQuickCloseAndAddCardShouldNotCrash() throws InterruptedException, ExecutionException, TimeoutException { - triggerUIAndWait(getReadyToPay()); - clickInPaymentMethodAndWait(R.id.payments_section, getReadyForInput()); + mPaymentRequestTestRule.triggerUIAndWait(mPaymentRequestTestRule.getReadyToPay()); + mPaymentRequestTestRule.clickInPaymentMethodAndWait( + R.id.payments_section, mPaymentRequestTestRule.getReadyForInput()); // Quickly press on [X] and then "add card." - int callCount = getDismissed().getCallCount(); + int callCount = mPaymentRequestTestRule.getDismissed().getCallCount(); ThreadUtils.runOnUiThreadBlocking(new Runnable() { @Override public void run() { - getPaymentRequestUI() + mPaymentRequestTestRule.getPaymentRequestUI() .getDialogForTest() .findViewById(R.id.close_button) .performClick(); - getPaymentRequestUI() + mPaymentRequestTestRule.getPaymentRequestUI() .getPaymentMethodSectionForTest() .findViewById(R.id.payments_add_option_button) .performClick(); } }); - getDismissed().waitForCallback(callCount); + mPaymentRequestTestRule.getDismissed().waitForCallback(callCount); - expectResultContains(new String[] {"Request cancelled"}); + mPaymentRequestTestRule.expectResultContains(new String[] {"Request cancelled"}); } /** Quickly pressing on "add card" and then "cancel" should not crash. */ + @Test @MediumTest @Feature({"Payments"}) public void testQuickAddCardAndCancelShouldNotCrash() throws InterruptedException, ExecutionException, TimeoutException { - triggerUIAndWait(getReadyToPay()); - clickInPaymentMethodAndWait(R.id.payments_section, getReadyForInput()); + mPaymentRequestTestRule.triggerUIAndWait(mPaymentRequestTestRule.getReadyToPay()); + mPaymentRequestTestRule.clickInPaymentMethodAndWait( + R.id.payments_section, mPaymentRequestTestRule.getReadyForInput()); // Quickly press on "add card" and then "cancel." - int callCount = getReadyToEdit().getCallCount(); + int callCount = mPaymentRequestTestRule.getReadyToEdit().getCallCount(); ThreadUtils.runOnUiThreadBlocking(new Runnable() { @Override public void run() { - getPaymentRequestUI() + mPaymentRequestTestRule.getPaymentRequestUI() .getPaymentMethodSectionForTest() .findViewById(R.id.payments_add_option_button) .performClick(); - getPaymentRequestUI() + mPaymentRequestTestRule.getPaymentRequestUI() .getDialogForTest() .findViewById(R.id.button_secondary) .performClick(); } }); - getReadyToEdit().waitForCallback(callCount); + mPaymentRequestTestRule.getReadyToEdit().waitForCallback(callCount); - clickInCardEditorAndWait(R.id.payments_edit_cancel_button, getReadyToPay()); - clickAndWait(R.id.close_button, getDismissed()); - expectResultContains(new String[] {"Request cancelled"}); + mPaymentRequestTestRule.clickInCardEditorAndWait( + R.id.payments_edit_cancel_button, mPaymentRequestTestRule.getReadyToPay()); + mPaymentRequestTestRule.clickAndWait( + R.id.close_button, mPaymentRequestTestRule.getDismissed()); + mPaymentRequestTestRule.expectResultContains(new String[] {"Request cancelled"}); } /** Quickly pressing on "cancel" and then "add card" should not crash. */ + @Test @MediumTest @Feature({"Payments"}) public void testQuickCancelAndAddCardShouldNotCrash() throws InterruptedException, ExecutionException, TimeoutException { - triggerUIAndWait(getReadyToPay()); - clickInPaymentMethodAndWait(R.id.payments_section, getReadyForInput()); + mPaymentRequestTestRule.triggerUIAndWait(mPaymentRequestTestRule.getReadyToPay()); + mPaymentRequestTestRule.clickInPaymentMethodAndWait( + R.id.payments_section, mPaymentRequestTestRule.getReadyForInput()); // Quickly press on "cancel" and then "add card." - int callCount = getDismissed().getCallCount(); + int callCount = mPaymentRequestTestRule.getDismissed().getCallCount(); ThreadUtils.runOnUiThreadBlocking(new Runnable() { @Override public void run() { - getPaymentRequestUI() + mPaymentRequestTestRule.getPaymentRequestUI() .getDialogForTest() .findViewById(R.id.button_secondary) .performClick(); - getPaymentRequestUI() + mPaymentRequestTestRule.getPaymentRequestUI() .getPaymentMethodSectionForTest() .findViewById(R.id.payments_add_option_button) .performClick(); } }); - getDismissed().waitForCallback(callCount); + mPaymentRequestTestRule.getDismissed().waitForCallback(callCount); - expectResultContains(new String[] {"Request cancelled"}); + mPaymentRequestTestRule.expectResultContains(new String[] {"Request cancelled"}); } /** * Quickly dismissing the dialog (via Android's back button, for example) and then pressing on * "pay" should not crash. */ + @Test @MediumTest @Feature({"Payments"}) public void testQuickDismissAndPayShouldNotCrash() throws InterruptedException, ExecutionException, TimeoutException { - triggerUIAndWait(getReadyToPay()); + mPaymentRequestTestRule.triggerUIAndWait(mPaymentRequestTestRule.getReadyToPay()); // Quickly dismiss and then press on "pay." - int callCount = getDismissed().getCallCount(); + int callCount = mPaymentRequestTestRule.getDismissed().getCallCount(); ThreadUtils.runOnUiThreadBlocking(new Runnable() { @Override public void run() { - getPaymentRequestUI().getDialogForTest().onBackPressed(); - getPaymentRequestUI() + mPaymentRequestTestRule.getPaymentRequestUI().getDialogForTest().onBackPressed(); + mPaymentRequestTestRule.getPaymentRequestUI() .getDialogForTest() .findViewById(R.id.button_primary) .performClick(); } }); - getDismissed().waitForCallback(callCount); + mPaymentRequestTestRule.getDismissed().waitForCallback(callCount); - expectResultContains(new String[] {"Request cancelled"}); + mPaymentRequestTestRule.expectResultContains(new String[] {"Request cancelled"}); } /** * Quickly dismissing the dialog (via Android's back button, for example) and then pressing on * [X] should not crash. */ + @Test @MediumTest @Feature({"Payments"}) public void testQuickDismissAndCloseShouldNotCrash() throws InterruptedException, ExecutionException, TimeoutException { - triggerUIAndWait(getReadyToPay()); + mPaymentRequestTestRule.triggerUIAndWait(mPaymentRequestTestRule.getReadyToPay()); // Quickly dismiss and then press on [X]. - int callCount = getDismissed().getCallCount(); + int callCount = mPaymentRequestTestRule.getDismissed().getCallCount(); ThreadUtils.runOnUiThreadBlocking(new Runnable() { @Override public void run() { - getPaymentRequestUI().getDialogForTest().onBackPressed(); - getPaymentRequestUI() + mPaymentRequestTestRule.getPaymentRequestUI().getDialogForTest().onBackPressed(); + mPaymentRequestTestRule.getPaymentRequestUI() .getDialogForTest() .findViewById(R.id.close_button) .performClick(); } }); - getDismissed().waitForCallback(callCount); + mPaymentRequestTestRule.getDismissed().waitForCallback(callCount); - expectResultContains(new String[] {"Request cancelled"}); + mPaymentRequestTestRule.expectResultContains(new String[] {"Request cancelled"}); } /** * Quickly pressing on [X] and then dismissing the dialog (via Android's back button, for * example) should not crash. */ + @Test @MediumTest @Feature({"Payments"}) public void testQuickCloseAndDismissShouldNotCrash() throws InterruptedException, ExecutionException, TimeoutException { - triggerUIAndWait(getReadyToPay()); + mPaymentRequestTestRule.triggerUIAndWait(mPaymentRequestTestRule.getReadyToPay()); // Quickly press on [X] and then dismiss. - int callCount = getDismissed().getCallCount(); + int callCount = mPaymentRequestTestRule.getDismissed().getCallCount(); ThreadUtils.runOnUiThreadBlocking(new Runnable() { @Override public void run() { - getPaymentRequestUI() + mPaymentRequestTestRule.getPaymentRequestUI() .getDialogForTest() .findViewById(R.id.close_button) .performClick(); - getPaymentRequestUI().getDialogForTest().onBackPressed(); + mPaymentRequestTestRule.getPaymentRequestUI().getDialogForTest().onBackPressed(); } }); - getDismissed().waitForCallback(callCount); + mPaymentRequestTestRule.getDismissed().waitForCallback(callCount); - expectResultContains(new String[] {"Request cancelled"}); + mPaymentRequestTestRule.expectResultContains(new String[] {"Request cancelled"}); } /** @@ -398,16 +487,17 @@ * results in the appropriate metric being logged in the PaymentRequest.RequestedInformation * histogram. */ + @Test @MediumTest @Feature({"Payments"}) - public void testRequestedInformationMetric() throws InterruptedException, ExecutionException, - TimeoutException { + public void testRequestedInformationMetric() + throws InterruptedException, ExecutionException, TimeoutException { // Start the Payment Request. - triggerUIAndWait(getReadyToPay()); + mPaymentRequestTestRule.triggerUIAndWait(mPaymentRequestTestRule.getReadyToPay()); // Make sure that only the appropriate enum value was logged. for (int i = 0; i < PaymentRequestMetrics.REQUESTED_INFORMATION_MAX; ++i) { - assertEquals((i == PaymentRequestMetrics.REQUESTED_INFORMATION_NONE ? 1 : 0), + Assert.assertEquals((i == PaymentRequestMetrics.REQUESTED_INFORMATION_NONE ? 1 : 0), RecordHistogram.getHistogramValueCountForTesting( "PaymentRequest.RequestedInformation", i)); }
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestPaymentAppAndCardsTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestPaymentAppAndCardsTest.java index b83292ab..59133030 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestPaymentAppAndCardsTest.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestPaymentAppAndCardsTest.java
@@ -4,14 +4,29 @@ package org.chromium.chrome.browser.payments; +import static org.chromium.chrome.browser.payments.PaymentRequestTestRule.DELAYED_RESPONSE; +import static org.chromium.chrome.browser.payments.PaymentRequestTestRule.HAVE_INSTRUMENTS; +import static org.chromium.chrome.browser.payments.PaymentRequestTestRule.IMMEDIATE_RESPONSE; +import static org.chromium.chrome.browser.payments.PaymentRequestTestRule.NO_INSTRUMENTS; + import android.content.DialogInterface; import android.support.test.filters.MediumTest; +import org.junit.Assert; +import org.junit.Rule; +import org.junit.Test; +import org.junit.runner.RunWith; + +import org.chromium.base.test.util.CommandLineFlags; import org.chromium.base.test.util.Feature; import org.chromium.chrome.R; +import org.chromium.chrome.browser.ChromeSwitches; import org.chromium.chrome.browser.autofill.AutofillTestHelper; import org.chromium.chrome.browser.autofill.PersonalDataManager.AutofillProfile; import org.chromium.chrome.browser.autofill.PersonalDataManager.CreditCard; +import org.chromium.chrome.browser.payments.PaymentRequestTestRule.MainActivityStartCallback; +import org.chromium.chrome.test.ChromeActivityTestRule; +import org.chromium.chrome.test.ChromeJUnit4ClassRunner; import java.util.concurrent.ExecutionException; import java.util.concurrent.TimeoutException; @@ -19,10 +34,15 @@ /** * A payment integration test for a merchant that requests payment via Bob Pay or cards. */ -public class PaymentRequestPaymentAppAndCardsTest extends PaymentRequestTestBase { - public PaymentRequestPaymentAppAndCardsTest() { - super("payment_request_bobpay_and_cards_test.html"); - } +@RunWith(ChromeJUnit4ClassRunner.class) +@CommandLineFlags.Add({ + ChromeSwitches.DISABLE_FIRST_RUN_EXPERIENCE, + ChromeActivityTestRule.DISABLE_NETWORK_PREDICTION_FLAG, +}) +public class PaymentRequestPaymentAppAndCardsTest implements MainActivityStartCallback { + @Rule + public PaymentRequestTestRule mPaymentRequestTestRule = + new PaymentRequestTestRule("payment_request_bobpay_and_cards_test.html", this); @Override public void onMainActivityStarted() throws InterruptedException, ExecutionException, @@ -45,10 +65,11 @@ * If Bob Pay does not have any instruments, show [visa, mastercard]. Here the payment app * responds quickly. */ + @Test @MediumTest @Feature({"Payments"}) - public void testNoInstrumentsInFastBobPay() throws InterruptedException, ExecutionException, - TimeoutException { + public void testNoInstrumentsInFastBobPay() + throws InterruptedException, ExecutionException, TimeoutException { runTest(NO_INSTRUMENTS, IMMEDIATE_RESPONSE); } @@ -56,10 +77,11 @@ * If Bob Pay does not have any instruments, show [visa, mastercard]. Here the payment app * responds slowly. */ + @Test @MediumTest @Feature({"Payments"}) - public void testNoInstrumentsInSlowBobPay() throws InterruptedException, ExecutionException, - TimeoutException { + public void testNoInstrumentsInSlowBobPay() + throws InterruptedException, ExecutionException, TimeoutException { runTest(NO_INSTRUMENTS, DELAYED_RESPONSE); } @@ -67,10 +89,11 @@ * If Bob Pay has instruments, show [bobpay, visa, mastercard]. Here the payment app responds * quickly. */ + @Test @MediumTest @Feature({"Payments"}) - public void testHaveInstrumentsInFastBobPay() throws InterruptedException, ExecutionException, - TimeoutException { + public void testHaveInstrumentsInFastBobPay() + throws InterruptedException, ExecutionException, TimeoutException { runTest(HAVE_INSTRUMENTS, IMMEDIATE_RESPONSE); } @@ -78,81 +101,97 @@ * If Bob Pay has instruments, show [bobpay, visa, mastercard]. Here the payment app responds * slowly. */ + @Test @MediumTest @Feature({"Payments"}) - public void testHaveInstrumentsInSlowBobPay() throws InterruptedException, ExecutionException, - TimeoutException { + public void testHaveInstrumentsInSlowBobPay() + throws InterruptedException, ExecutionException, TimeoutException { runTest(HAVE_INSTRUMENTS, DELAYED_RESPONSE); } /** Test that going into the editor and cancelling will leave the row checked. */ + @Test @MediumTest @Feature({"Payments"}) public void testEditPaymentMethodAndCancelEditorShouldKeepCardSelected() throws InterruptedException, ExecutionException, TimeoutException { - triggerUIAndWait(getReadyToPay()); - clickInPaymentMethodAndWait(R.id.payments_section, getReadyForInput()); - expectPaymentMethodRowIsSelected(0); - clickInPaymentMethodAndWait(R.id.payments_add_option_button, getReadyToEdit()); + mPaymentRequestTestRule.triggerUIAndWait(mPaymentRequestTestRule.getReadyToPay()); + mPaymentRequestTestRule.clickInPaymentMethodAndWait( + R.id.payments_section, mPaymentRequestTestRule.getReadyForInput()); + mPaymentRequestTestRule.expectPaymentMethodRowIsSelected(0); + mPaymentRequestTestRule.clickInPaymentMethodAndWait( + R.id.payments_add_option_button, mPaymentRequestTestRule.getReadyToEdit()); // Cancel the editor. - clickInCardEditorAndWait(R.id.payments_edit_cancel_button, getReadyToPay()); + mPaymentRequestTestRule.clickInCardEditorAndWait( + R.id.payments_edit_cancel_button, mPaymentRequestTestRule.getReadyToPay()); // Expect the existing row to still be selected in the Shipping Address section. - expectPaymentMethodRowIsSelected(0); + mPaymentRequestTestRule.expectPaymentMethodRowIsSelected(0); } /** Test that going into "add" flow editor and cancelling will leave existing row checked. */ + @Test @MediumTest @Feature({"Payments"}) public void testAddPaymentMethodAndCancelEditorShouldKeepExistingCardSelected() throws InterruptedException, ExecutionException, TimeoutException { - triggerUIAndWait(getReadyToPay()); - clickInPaymentMethodAndWait(R.id.payments_section, getReadyForInput()); - expectPaymentMethodRowIsSelected(0); - clickInPaymentMethodAndWait(R.id.payments_open_editor_pencil_button, getReadyToEdit()); + mPaymentRequestTestRule.triggerUIAndWait(mPaymentRequestTestRule.getReadyToPay()); + mPaymentRequestTestRule.clickInPaymentMethodAndWait( + R.id.payments_section, mPaymentRequestTestRule.getReadyForInput()); + mPaymentRequestTestRule.expectPaymentMethodRowIsSelected(0); + mPaymentRequestTestRule.clickInPaymentMethodAndWait( + R.id.payments_open_editor_pencil_button, mPaymentRequestTestRule.getReadyToEdit()); // Cancel the editor. - clickInCardEditorAndWait(R.id.payments_edit_cancel_button, getReadyToPay()); + mPaymentRequestTestRule.clickInCardEditorAndWait( + R.id.payments_edit_cancel_button, mPaymentRequestTestRule.getReadyToPay()); // Expect the row to still be selected in the Shipping Address section. - expectPaymentMethodRowIsSelected(0); + mPaymentRequestTestRule.expectPaymentMethodRowIsSelected(0); } private void runTest(int instrumentPresence, int responseSpeed) throws InterruptedException, ExecutionException, TimeoutException { - installPaymentApp(instrumentPresence, responseSpeed); - triggerUIAndWait(getReadyToPay()); - clickInPaymentMethodAndWait(R.id.payments_section, getReadyForInput()); + mPaymentRequestTestRule.installPaymentApp(instrumentPresence, responseSpeed); + mPaymentRequestTestRule.triggerUIAndWait(mPaymentRequestTestRule.getReadyToPay()); + mPaymentRequestTestRule.clickInPaymentMethodAndWait( + R.id.payments_section, mPaymentRequestTestRule.getReadyForInput()); // Check the number of instruments. - assertEquals( - instrumentPresence == HAVE_INSTRUMENTS ? 3 : 2, getNumberOfPaymentInstruments()); + Assert.assertEquals(instrumentPresence == HAVE_INSTRUMENTS ? 3 : 2, + mPaymentRequestTestRule.getNumberOfPaymentInstruments()); // Check the labels of the instruments. int i = 0; if (instrumentPresence == HAVE_INSTRUMENTS) { - assertEquals("https://bobpay.com", getPaymentInstrumentLabel(i++)); + Assert.assertEquals( + "https://bobpay.com", mPaymentRequestTestRule.getPaymentInstrumentLabel(i++)); } // \u0020\...\u2006 is four dots ellipsis. - assertEquals( + Assert.assertEquals( "Visa\u0020\u0020\u2022\u2006\u2022\u2006\u2022\u2006\u2022\u20061111\nJon Doe", - getPaymentInstrumentLabel(i++)); - assertEquals( + mPaymentRequestTestRule.getPaymentInstrumentLabel(i++)); + Assert.assertEquals( "MasterCard\u0020\u0020\u2022\u2006\u2022\u2006\u2022\u2006\u2022\u20065454\n" - + "Jon Doe\nBilling address required", - getPaymentInstrumentLabel(i++)); + + "Jon Doe\nBilling address required", + mPaymentRequestTestRule.getPaymentInstrumentLabel(i++)); // Check the output of the selected instrument. if (instrumentPresence == HAVE_INSTRUMENTS) { - clickAndWait(R.id.button_primary, getDismissed()); - expectResultContains(new String[]{"https://bobpay.com", "\"transaction\"", "1337"}); + mPaymentRequestTestRule.clickAndWait( + R.id.button_primary, mPaymentRequestTestRule.getDismissed()); + mPaymentRequestTestRule.expectResultContains( + new String[] {"https://bobpay.com", "\"transaction\"", "1337"}); } else { - clickAndWait(R.id.button_primary, getReadyForUnmaskInput()); - setTextInCardUnmaskDialogAndWait(R.id.card_unmask_input, "123", getReadyToUnmask()); - clickCardUnmaskButtonAndWait(DialogInterface.BUTTON_POSITIVE, getDismissed()); - expectResultContains(new String[] {"Jon Doe", "4111111111111111", "12", "2050", "visa", - "123"}); + mPaymentRequestTestRule.clickAndWait( + R.id.button_primary, mPaymentRequestTestRule.getReadyForUnmaskInput()); + mPaymentRequestTestRule.setTextInCardUnmaskDialogAndWait( + R.id.card_unmask_input, "123", mPaymentRequestTestRule.getReadyToUnmask()); + mPaymentRequestTestRule.clickCardUnmaskButtonAndWait( + DialogInterface.BUTTON_POSITIVE, mPaymentRequestTestRule.getDismissed()); + mPaymentRequestTestRule.expectResultContains( + new String[] {"Jon Doe", "4111111111111111", "12", "2050", "visa", "123"}); } } }
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestPaymentAppTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestPaymentAppTest.java index e7a9c23..07b0d79 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestPaymentAppTest.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestPaymentAppTest.java
@@ -4,14 +4,28 @@ package org.chromium.chrome.browser.payments; +import static org.chromium.chrome.browser.payments.PaymentRequestTestRule.DELAYED_CREATION; +import static org.chromium.chrome.browser.payments.PaymentRequestTestRule.DELAYED_RESPONSE; +import static org.chromium.chrome.browser.payments.PaymentRequestTestRule.HAVE_INSTRUMENTS; +import static org.chromium.chrome.browser.payments.PaymentRequestTestRule.IMMEDIATE_RESPONSE; +import static org.chromium.chrome.browser.payments.PaymentRequestTestRule.NO_INSTRUMENTS; + import android.support.test.filters.MediumTest; +import org.junit.Rule; +import org.junit.Test; +import org.junit.runner.RunWith; + import org.chromium.base.ThreadUtils; +import org.chromium.base.test.util.CommandLineFlags; import org.chromium.base.test.util.Feature; import org.chromium.chrome.R; +import org.chromium.chrome.browser.ChromeSwitches; import org.chromium.chrome.browser.payments.PaymentAppFactory.PaymentAppCreatedCallback; import org.chromium.chrome.browser.payments.PaymentAppFactory.PaymentAppFactoryAddition; import org.chromium.chrome.browser.payments.PaymentRequestTestCommon.TestPay; +import org.chromium.chrome.test.ChromeActivityTestRule; +import org.chromium.chrome.test.ChromeJUnit4ClassRunner; import org.chromium.content_public.browser.WebContents; import java.util.Arrays; @@ -22,57 +36,62 @@ /** * A payment integration test for a merchant that requests payment via Bob Pay. */ -public class PaymentRequestPaymentAppTest extends PaymentRequestTestBase { - public PaymentRequestPaymentAppTest() { - super("payment_request_bobpay_test.html"); - } - - @Override - public void onMainActivityStarted() throws InterruptedException, ExecutionException, - TimeoutException {} +@RunWith(ChromeJUnit4ClassRunner.class) +@CommandLineFlags.Add({ + ChromeSwitches.DISABLE_FIRST_RUN_EXPERIENCE, + ChromeActivityTestRule.DISABLE_NETWORK_PREDICTION_FLAG, +}) +public class PaymentRequestPaymentAppTest { + @Rule + public PaymentRequestTestRule mPaymentRequestTestRule = + new PaymentRequestTestRule("payment_request_bobpay_test.html"); /** If no payment methods are supported, reject the show() promise. */ + @Test @MediumTest @Feature({"Payments"}) - public void testNoSupportedPaymentMethods() throws InterruptedException, ExecutionException, - TimeoutException { - openPageAndClickBuyAndWait(getShowFailed()); - expectResultContains( - new String[]{"show() rejected", "The payment method is not supported"}); + public void testNoSupportedPaymentMethods() + throws InterruptedException, ExecutionException, TimeoutException { + mPaymentRequestTestRule.openPageAndClickBuyAndWait(mPaymentRequestTestRule.getShowFailed()); + mPaymentRequestTestRule.expectResultContains( + new String[] {"show() rejected", "The payment method is not supported"}); } /** * If Bob Pay does not have any instruments, reject the show() promise. Here Bob Pay responds to * Chrome immediately. */ + @Test @MediumTest @Feature({"Payments"}) - public void testNoInstrumentsInFastBobPay() throws InterruptedException, ExecutionException, - TimeoutException { - installPaymentApp(NO_INSTRUMENTS, IMMEDIATE_RESPONSE); - openPageAndClickBuyAndWait(getShowFailed()); - expectResultContains( - new String[]{"show() rejected", "The payment method is not supported"}); + public void testNoInstrumentsInFastBobPay() + throws InterruptedException, ExecutionException, TimeoutException { + mPaymentRequestTestRule.installPaymentApp(NO_INSTRUMENTS, IMMEDIATE_RESPONSE); + mPaymentRequestTestRule.openPageAndClickBuyAndWait(mPaymentRequestTestRule.getShowFailed()); + mPaymentRequestTestRule.expectResultContains( + new String[] {"show() rejected", "The payment method is not supported"}); } /** * If Bob Pay does not have any instruments, reject the show() promise. Here Bob Pay responds to * Chrome after a slight delay. */ + @Test @MediumTest @Feature({"Payments"}) - public void testNoInstrumentsInSlowBobPay() throws InterruptedException, ExecutionException, - TimeoutException { - installPaymentApp(NO_INSTRUMENTS, DELAYED_RESPONSE); - openPageAndClickBuyAndWait(getShowFailed()); - expectResultContains( - new String[]{"show() rejected", "The payment method is not supported"}); + public void testNoInstrumentsInSlowBobPay() + throws InterruptedException, ExecutionException, TimeoutException { + mPaymentRequestTestRule.installPaymentApp(NO_INSTRUMENTS, DELAYED_RESPONSE); + mPaymentRequestTestRule.openPageAndClickBuyAndWait(mPaymentRequestTestRule.getShowFailed()); + mPaymentRequestTestRule.expectResultContains( + new String[] {"show() rejected", "The payment method is not supported"}); } /** * If the payment app responds with more instruments after the UI has been dismissed, don't * crash. */ + @Test @MediumTest @Feature({"Payments"}) public void testPaymentWithInstrumentsAppResponseAfterDismissShouldNotCrash() @@ -87,20 +106,23 @@ callback.onAllPaymentAppsCreated(); } }); - triggerUIAndWait(getReadyForInput()); - clickAndWait(R.id.close_button, getDismissed()); + mPaymentRequestTestRule.triggerUIAndWait(mPaymentRequestTestRule.getReadyForInput()); + mPaymentRequestTestRule.clickAndWait( + R.id.close_button, mPaymentRequestTestRule.getDismissed()); ThreadUtils.runOnUiThreadBlocking(new Runnable() { @Override public void run() { app.respond(); } }); - expectResultContains(new String[]{"show() rejected", "Request cancelled"}); + mPaymentRequestTestRule.expectResultContains( + new String[] {"show() rejected", "Request cancelled"}); } /** * If the payment app responds with no instruments after the UI has been dismissed, don't crash. */ + @Test @MediumTest @Feature({"Payments"}) public void testPaymentAppNoInstrumentsResponseAfterDismissShouldNotCrash() @@ -115,72 +137,84 @@ callback.onAllPaymentAppsCreated(); } }); - openPageAndClickBuyAndWait(getShowFailed()); + mPaymentRequestTestRule.openPageAndClickBuyAndWait(mPaymentRequestTestRule.getShowFailed()); ThreadUtils.runOnUiThreadBlocking(new Runnable() { @Override public void run() { app.respond(); } }); - expectResultContains( - new String[]{"show() rejected", "The payment method is not supported"}); + mPaymentRequestTestRule.expectResultContains( + new String[] {"show() rejected", "The payment method is not supported"}); } /** * If Bob Pay is supported and installed, user should be able to pay with it. Here Bob Pay * responds to Chrome immediately. */ + @Test @MediumTest @Feature({"Payments"}) - public void testPayViaFastBobPay() throws InterruptedException, ExecutionException, - TimeoutException { - installPaymentApp(HAVE_INSTRUMENTS, IMMEDIATE_RESPONSE); - triggerUIAndWait(getReadyToPay()); - clickAndWait(R.id.button_primary, getDismissed()); - expectResultContains(new String[]{"https://bobpay.com", "\"transaction\"", "1337"}); + public void testPayViaFastBobPay() + throws InterruptedException, ExecutionException, TimeoutException { + mPaymentRequestTestRule.installPaymentApp(HAVE_INSTRUMENTS, IMMEDIATE_RESPONSE); + mPaymentRequestTestRule.triggerUIAndWait(mPaymentRequestTestRule.getReadyToPay()); + mPaymentRequestTestRule.clickAndWait( + R.id.button_primary, mPaymentRequestTestRule.getDismissed()); + mPaymentRequestTestRule.expectResultContains( + new String[] {"https://bobpay.com", "\"transaction\"", "1337"}); } /** * If Bob Pay is supported and installed, user should be able to pay with it. Here Bob Pay * responds to Chrome after a slight delay. */ + @Test @MediumTest @Feature({"Payments"}) - public void testPayViaSlowBobPay() throws InterruptedException, ExecutionException, - TimeoutException { - installPaymentApp(HAVE_INSTRUMENTS, DELAYED_RESPONSE); - triggerUIAndWait(getReadyToPay()); - clickAndWait(R.id.button_primary, getDismissed()); - expectResultContains(new String[]{"https://bobpay.com", "\"transaction\"", "1337"}); + public void testPayViaSlowBobPay() + throws InterruptedException, ExecutionException, TimeoutException { + mPaymentRequestTestRule.installPaymentApp(HAVE_INSTRUMENTS, DELAYED_RESPONSE); + mPaymentRequestTestRule.triggerUIAndWait(mPaymentRequestTestRule.getReadyToPay()); + mPaymentRequestTestRule.clickAndWait( + R.id.button_primary, mPaymentRequestTestRule.getDismissed()); + mPaymentRequestTestRule.expectResultContains( + new String[] {"https://bobpay.com", "\"transaction\"", "1337"}); } /** * Test payment with a Bob Pay that is created with a delay, but responds immediately * to getInstruments. */ + @Test @MediumTest @Feature({"Payments"}) public void testPayViaDelayedFastBobPay() throws InterruptedException, ExecutionException, TimeoutException { - installPaymentApp( + mPaymentRequestTestRule.installPaymentApp( "https://bobpay.com", HAVE_INSTRUMENTS, IMMEDIATE_RESPONSE, DELAYED_CREATION); - triggerUIAndWait(getReadyToPay()); - clickAndWait(R.id.button_primary, getDismissed()); - expectResultContains(new String[] {"https://bobpay.com", "\"transaction\"", "1337"}); + mPaymentRequestTestRule.triggerUIAndWait(mPaymentRequestTestRule.getReadyToPay()); + mPaymentRequestTestRule.clickAndWait( + R.id.button_primary, mPaymentRequestTestRule.getDismissed()); + mPaymentRequestTestRule.expectResultContains( + new String[] {"https://bobpay.com", "\"transaction\"", "1337"}); } /** * Test payment with a Bob Pay that is created with a delay, and responds slowly to * getInstruments. */ + @Test @MediumTest @Feature({"Payments"}) public void testPayViaDelayedSlowBobPay() throws InterruptedException, ExecutionException, TimeoutException { - installPaymentApp( + mPaymentRequestTestRule.installPaymentApp( "https://bobpay.com", HAVE_INSTRUMENTS, DELAYED_RESPONSE, DELAYED_CREATION); - triggerUIAndWait(getReadyToPay()); - clickAndWait(R.id.button_primary, getDismissed()); - expectResultContains(new String[] {"https://bobpay.com", "\"transaction\"", "1337"}); + mPaymentRequestTestRule.triggerUIAndWait(mPaymentRequestTestRule.getReadyToPay()); + mPaymentRequestTestRule.clickAndWait( + R.id.button_primary, mPaymentRequestTestRule.getDismissed()); + mPaymentRequestTestRule.expectResultContains( + new String[] {"https://bobpay.com", "\"transaction\"", "1337"}); } }
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestPaymentAppUiSkipPreloadTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestPaymentAppUiSkipPreloadTest.java index aee032c..cd64626 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestPaymentAppUiSkipPreloadTest.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestPaymentAppUiSkipPreloadTest.java
@@ -4,9 +4,22 @@ package org.chromium.chrome.browser.payments; +import static org.chromium.chrome.browser.payments.PaymentRequestTestRule.DELAYED_CREATION; +import static org.chromium.chrome.browser.payments.PaymentRequestTestRule.DELAYED_RESPONSE; +import static org.chromium.chrome.browser.payments.PaymentRequestTestRule.HAVE_INSTRUMENTS; +import static org.chromium.chrome.browser.payments.PaymentRequestTestRule.IMMEDIATE_RESPONSE; + import android.support.test.filters.MediumTest; +import org.junit.Rule; +import org.junit.Test; +import org.junit.runner.RunWith; + +import org.chromium.base.test.util.CommandLineFlags; import org.chromium.base.test.util.Feature; +import org.chromium.chrome.browser.ChromeSwitches; +import org.chromium.chrome.test.ChromeActivityTestRule; +import org.chromium.chrome.test.ChromeJUnit4ClassRunner; import java.util.concurrent.ExecutionException; import java.util.concurrent.TimeoutException; @@ -16,66 +29,75 @@ * single payment app UI skip optimization in addition to preloading PaymentRequest even before the * "Buy" button is clicked. */ -public class PaymentRequestPaymentAppUiSkipPreloadTest extends PaymentRequestTestBase { - public PaymentRequestPaymentAppUiSkipPreloadTest() { - super("payment_request_bobpay_ui_skip_preload_test.html"); - } - - @Override - public void onMainActivityStarted() - throws InterruptedException, ExecutionException, TimeoutException {} +@RunWith(ChromeJUnit4ClassRunner.class) +@CommandLineFlags.Add({ + ChromeSwitches.DISABLE_FIRST_RUN_EXPERIENCE, + ChromeActivityTestRule.DISABLE_NETWORK_PREDICTION_FLAG, +}) +public class PaymentRequestPaymentAppUiSkipPreloadTest { + @Rule + public PaymentRequestTestRule mPaymentRequestTestRule = + new PaymentRequestTestRule("payment_request_bobpay_ui_skip_preload_test.html"); /** * If Bob Pay is supported and installed, user should be able to pay with it. Here Bob Pay * responds to Chrome immediately. */ + @Test @MediumTest @Feature({"Payments"}) public void testPayViaFastBobPay() throws InterruptedException, ExecutionException, TimeoutException { - installPaymentApp(HAVE_INSTRUMENTS, IMMEDIATE_RESPONSE); - openPageAndClickBuyAndWait(getDismissed()); - expectResultContains(new String[] {"https://bobpay.com", "\"transaction\"", "1337"}); + mPaymentRequestTestRule.installPaymentApp(HAVE_INSTRUMENTS, IMMEDIATE_RESPONSE); + mPaymentRequestTestRule.openPageAndClickBuyAndWait(mPaymentRequestTestRule.getDismissed()); + mPaymentRequestTestRule.expectResultContains( + new String[] {"https://bobpay.com", "\"transaction\"", "1337"}); } /** * If Bob Pay is supported and installed, user should be able to pay with it. Here Bob Pay * responds to Chrome after a slight delay. */ + @Test @MediumTest @Feature({"Payments"}) public void testPayViaSlowBobPay() throws InterruptedException, ExecutionException, TimeoutException { - installPaymentApp(HAVE_INSTRUMENTS, DELAYED_RESPONSE); - openPageAndClickBuyAndWait(getDismissed()); - expectResultContains(new String[] {"https://bobpay.com", "\"transaction\"", "1337"}); + mPaymentRequestTestRule.installPaymentApp(HAVE_INSTRUMENTS, DELAYED_RESPONSE); + mPaymentRequestTestRule.openPageAndClickBuyAndWait(mPaymentRequestTestRule.getDismissed()); + mPaymentRequestTestRule.expectResultContains( + new String[] {"https://bobpay.com", "\"transaction\"", "1337"}); } /** * Test payment with a Bob Pay that is created with a delay, but responds immediately * to getInstruments. */ + @Test @MediumTest @Feature({"Payments"}) public void testPayViaDelayedFastBobPay() throws InterruptedException, ExecutionException, TimeoutException { - installPaymentApp( + mPaymentRequestTestRule.installPaymentApp( "https://bobpay.com", HAVE_INSTRUMENTS, IMMEDIATE_RESPONSE, DELAYED_CREATION); - openPageAndClickBuyAndWait(getDismissed()); - expectResultContains(new String[] {"https://bobpay.com", "\"transaction\"", "1337"}); + mPaymentRequestTestRule.openPageAndClickBuyAndWait(mPaymentRequestTestRule.getDismissed()); + mPaymentRequestTestRule.expectResultContains( + new String[] {"https://bobpay.com", "\"transaction\"", "1337"}); } /** * Test payment with a Bob Pay that is created with a delay, and responds slowly to * getInstruments. */ + @Test @MediumTest @Feature({"Payments"}) public void testPayViaDelayedSlowBobPay() throws InterruptedException, ExecutionException, TimeoutException { - installPaymentApp( + mPaymentRequestTestRule.installPaymentApp( "https://bobpay.com", HAVE_INSTRUMENTS, DELAYED_RESPONSE, DELAYED_CREATION); - openPageAndClickBuyAndWait(getDismissed()); - expectResultContains(new String[] {"https://bobpay.com", "\"transaction\"", "1337"}); + mPaymentRequestTestRule.openPageAndClickBuyAndWait(mPaymentRequestTestRule.getDismissed()); + mPaymentRequestTestRule.expectResultContains( + new String[] {"https://bobpay.com", "\"transaction\"", "1337"}); } }
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestPaymentAppUiSkipTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestPaymentAppUiSkipTest.java index 74f778c1..288f526f 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestPaymentAppUiSkipTest.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestPaymentAppUiSkipTest.java
@@ -4,9 +4,22 @@ package org.chromium.chrome.browser.payments; +import static org.chromium.chrome.browser.payments.PaymentRequestTestRule.DELAYED_CREATION; +import static org.chromium.chrome.browser.payments.PaymentRequestTestRule.DELAYED_RESPONSE; +import static org.chromium.chrome.browser.payments.PaymentRequestTestRule.HAVE_INSTRUMENTS; +import static org.chromium.chrome.browser.payments.PaymentRequestTestRule.IMMEDIATE_RESPONSE; + import android.support.test.filters.MediumTest; +import org.junit.Rule; +import org.junit.Test; +import org.junit.runner.RunWith; + +import org.chromium.base.test.util.CommandLineFlags; import org.chromium.base.test.util.Feature; +import org.chromium.chrome.browser.ChromeSwitches; +import org.chromium.chrome.test.ChromeActivityTestRule; +import org.chromium.chrome.test.ChromeJUnit4ClassRunner; import java.util.concurrent.ExecutionException; import java.util.concurrent.TimeoutException; @@ -15,66 +28,75 @@ * A payment integration test for a merchant that requests payment via Bob Pay when performing the * single payment app UI skip optimization. */ -public class PaymentRequestPaymentAppUiSkipTest extends PaymentRequestTestBase { - public PaymentRequestPaymentAppUiSkipTest() { - super("payment_request_bobpay_ui_skip_test.html"); - } - - @Override - public void onMainActivityStarted() - throws InterruptedException, ExecutionException, TimeoutException {} +@RunWith(ChromeJUnit4ClassRunner.class) +@CommandLineFlags.Add({ + ChromeSwitches.DISABLE_FIRST_RUN_EXPERIENCE, + ChromeActivityTestRule.DISABLE_NETWORK_PREDICTION_FLAG, +}) +public class PaymentRequestPaymentAppUiSkipTest { + @Rule + public PaymentRequestTestRule mPaymentRequestTestRule = + new PaymentRequestTestRule("payment_request_bobpay_ui_skip_test.html"); /** * If Bob Pay is supported and installed, user should be able to pay with it. Here Bob Pay * responds to Chrome immediately. */ + @Test @MediumTest @Feature({"Payments"}) public void testPayViaFastBobPay() throws InterruptedException, ExecutionException, TimeoutException { - installPaymentApp(HAVE_INSTRUMENTS, IMMEDIATE_RESPONSE); - openPageAndClickBuyAndWait(getDismissed()); - expectResultContains(new String[] {"https://bobpay.com", "\"transaction\"", "1337"}); + mPaymentRequestTestRule.installPaymentApp(HAVE_INSTRUMENTS, IMMEDIATE_RESPONSE); + mPaymentRequestTestRule.openPageAndClickBuyAndWait(mPaymentRequestTestRule.getDismissed()); + mPaymentRequestTestRule.expectResultContains( + new String[] {"https://bobpay.com", "\"transaction\"", "1337"}); } /** * If Bob Pay is supported and installed, user should be able to pay with it. Here Bob Pay * responds to Chrome after a slight delay. */ + @Test @MediumTest @Feature({"Payments"}) public void testPayViaSlowBobPay() throws InterruptedException, ExecutionException, TimeoutException { - installPaymentApp(HAVE_INSTRUMENTS, DELAYED_RESPONSE); - openPageAndClickBuyAndWait(getDismissed()); - expectResultContains(new String[] {"https://bobpay.com", "\"transaction\"", "1337"}); + mPaymentRequestTestRule.installPaymentApp(HAVE_INSTRUMENTS, DELAYED_RESPONSE); + mPaymentRequestTestRule.openPageAndClickBuyAndWait(mPaymentRequestTestRule.getDismissed()); + mPaymentRequestTestRule.expectResultContains( + new String[] {"https://bobpay.com", "\"transaction\"", "1337"}); } /** * Test payment with a Bob Pay that is created with a delay, but responds immediately * to getInstruments. */ + @Test @MediumTest @Feature({"Payments"}) public void testPayViaDelayedFastBobPay() throws InterruptedException, ExecutionException, TimeoutException { - installPaymentApp( + mPaymentRequestTestRule.installPaymentApp( "https://bobpay.com", HAVE_INSTRUMENTS, IMMEDIATE_RESPONSE, DELAYED_CREATION); - openPageAndClickBuyAndWait(getDismissed()); - expectResultContains(new String[] {"https://bobpay.com", "\"transaction\"", "1337"}); + mPaymentRequestTestRule.openPageAndClickBuyAndWait(mPaymentRequestTestRule.getDismissed()); + mPaymentRequestTestRule.expectResultContains( + new String[] {"https://bobpay.com", "\"transaction\"", "1337"}); } /** * Test payment with a Bob Pay that is created with a delay, and responds slowly to * getInstruments. */ + @Test @MediumTest @Feature({"Payments"}) public void testPayViaDelayedSlowBobPay() throws InterruptedException, ExecutionException, TimeoutException { - installPaymentApp( + mPaymentRequestTestRule.installPaymentApp( "https://bobpay.com", HAVE_INSTRUMENTS, DELAYED_RESPONSE, DELAYED_CREATION); - openPageAndClickBuyAndWait(getDismissed()); - expectResultContains(new String[] {"https://bobpay.com", "\"transaction\"", "1337"}); + mPaymentRequestTestRule.openPageAndClickBuyAndWait(mPaymentRequestTestRule.getDismissed()); + mPaymentRequestTestRule.expectResultContains( + new String[] {"https://bobpay.com", "\"transaction\"", "1337"}); } }
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestPaymentAppsSortingTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestPaymentAppsSortingTest.java index 8857866e..86a7bff 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestPaymentAppsSortingTest.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestPaymentAppsSortingTest.java
@@ -4,16 +4,29 @@ package org.chromium.chrome.browser.payments; +import static org.chromium.chrome.browser.payments.PaymentRequestTestRule.HAVE_INSTRUMENTS; +import static org.chromium.chrome.browser.payments.PaymentRequestTestRule.IMMEDIATE_RESPONSE; + import android.support.test.filters.MediumTest; +import org.junit.Assert; +import org.junit.Rule; +import org.junit.Test; +import org.junit.runner.RunWith; + +import org.chromium.base.test.util.CommandLineFlags; import org.chromium.base.test.util.Feature; import org.chromium.chrome.R; +import org.chromium.chrome.browser.ChromeSwitches; import org.chromium.chrome.browser.autofill.AutofillTestHelper; import org.chromium.chrome.browser.autofill.PersonalDataManager.AutofillProfile; import org.chromium.chrome.browser.autofill.PersonalDataManager.CreditCard; import org.chromium.chrome.browser.payments.PaymentAppFactory.PaymentAppCreatedCallback; import org.chromium.chrome.browser.payments.PaymentAppFactory.PaymentAppFactoryAddition; import org.chromium.chrome.browser.payments.PaymentRequestTestCommon.TestPay; +import org.chromium.chrome.browser.payments.PaymentRequestTestRule.MainActivityStartCallback; +import org.chromium.chrome.test.ChromeActivityTestRule; +import org.chromium.chrome.test.ChromeJUnit4ClassRunner; import org.chromium.content_public.browser.WebContents; import java.util.Arrays; @@ -22,10 +35,15 @@ import java.util.concurrent.TimeoutException; /** A payment integration test that sorting payment apps and instruments by frecency. */ -public class PaymentRequestPaymentAppsSortingTest extends PaymentRequestTestBase { - public PaymentRequestPaymentAppsSortingTest() { - super("payment_request_alicepay_bobpay_charliepay_and_cards_test.html"); - } +@RunWith(ChromeJUnit4ClassRunner.class) +@CommandLineFlags.Add({ + ChromeSwitches.DISABLE_FIRST_RUN_EXPERIENCE, + ChromeActivityTestRule.DISABLE_NETWORK_PREDICTION_FLAG, +}) +public class PaymentRequestPaymentAppsSortingTest implements MainActivityStartCallback { + @Rule + public PaymentRequestTestRule mPaymentRequestTestRule = new PaymentRequestTestRule( + "payment_request_alicepay_bobpay_charliepay_and_cards_test.html", this); @Override public void onMainActivityStarted() @@ -41,6 +59,7 @@ "" /* serverId */)); } + @Test @MediumTest @Feature({"Payments"}) public void testPaymentAppsSortingByFrecency() @@ -66,12 +85,16 @@ String appBCharliePayId = appB.getAppIdentifier() + "https://charliepay.com"; // The initial records for all payment methods are zeroes. - assertEquals(0, PaymentPreferencesUtil.getPaymentInstrumentUseCount(appAAlicePayId)); - assertEquals(0, PaymentPreferencesUtil.getPaymentInstrumentUseCount(appABobPayId)); - assertEquals(0, PaymentPreferencesUtil.getPaymentInstrumentUseCount(appBCharliePayId)); - assertEquals(0, PaymentPreferencesUtil.getPaymentInstrumentLastUseDate(appAAlicePayId)); - assertEquals(0, PaymentPreferencesUtil.getPaymentInstrumentLastUseDate(appABobPayId)); - assertEquals(0, PaymentPreferencesUtil.getPaymentInstrumentLastUseDate(appBCharliePayId)); + Assert.assertEquals(0, PaymentPreferencesUtil.getPaymentInstrumentUseCount(appAAlicePayId)); + Assert.assertEquals(0, PaymentPreferencesUtil.getPaymentInstrumentUseCount(appABobPayId)); + Assert.assertEquals( + 0, PaymentPreferencesUtil.getPaymentInstrumentUseCount(appBCharliePayId)); + Assert.assertEquals( + 0, PaymentPreferencesUtil.getPaymentInstrumentLastUseDate(appAAlicePayId)); + Assert.assertEquals( + 0, PaymentPreferencesUtil.getPaymentInstrumentLastUseDate(appABobPayId)); + Assert.assertEquals( + 0, PaymentPreferencesUtil.getPaymentInstrumentLastUseDate(appBCharliePayId)); // Sets Alice Pay use count and use date to 5. Sets Bob Pay use count and use date to 10. // Sets Charlie Pay use count and use date to 15. @@ -82,57 +105,77 @@ PaymentPreferencesUtil.setPaymentInstrumentUseCountForTest(appBCharliePayId, 15); PaymentPreferencesUtil.setPaymentInstrumentLastUseDate(appBCharliePayId, 15); - triggerUIAndWait(getReadyToPay()); - clickInPaymentMethodAndWait(R.id.payments_section, getReadyForInput()); + mPaymentRequestTestRule.triggerUIAndWait(mPaymentRequestTestRule.getReadyToPay()); + mPaymentRequestTestRule.clickInPaymentMethodAndWait( + R.id.payments_section, mPaymentRequestTestRule.getReadyForInput()); // Checks Charlie Pay is listed at the first position. - assertEquals(4, getNumberOfPaymentInstruments()); - assertEquals("https://charliepay.com", getPaymentInstrumentLabel(0)); - assertEquals("https://bobpay.com", getPaymentInstrumentLabel(1)); - assertEquals("https://alicepay.com", getPaymentInstrumentLabel(2)); - assertEquals( + Assert.assertEquals(4, mPaymentRequestTestRule.getNumberOfPaymentInstruments()); + Assert.assertEquals( + "https://charliepay.com", mPaymentRequestTestRule.getPaymentInstrumentLabel(0)); + Assert.assertEquals( + "https://bobpay.com", mPaymentRequestTestRule.getPaymentInstrumentLabel(1)); + Assert.assertEquals( + "https://alicepay.com", mPaymentRequestTestRule.getPaymentInstrumentLabel(2)); + Assert.assertEquals( "Visa\u0020\u0020\u2022\u2006\u2022\u2006\u2022\u2006\u2022\u20061111\nJon Doe", - getPaymentInstrumentLabel(3)); + mPaymentRequestTestRule.getPaymentInstrumentLabel(3)); // Cancel the Payment Request. - clickAndWait(R.id.button_secondary, getDismissed()); + mPaymentRequestTestRule.clickAndWait( + R.id.button_secondary, mPaymentRequestTestRule.getDismissed()); // Checks the records for all payment instruments haven't been changed. - assertEquals(5, PaymentPreferencesUtil.getPaymentInstrumentUseCount(appAAlicePayId)); - assertEquals(10, PaymentPreferencesUtil.getPaymentInstrumentUseCount(appABobPayId)); - assertEquals(15, PaymentPreferencesUtil.getPaymentInstrumentUseCount(appBCharliePayId)); - assertEquals(5, PaymentPreferencesUtil.getPaymentInstrumentLastUseDate(appAAlicePayId)); - assertEquals(10, PaymentPreferencesUtil.getPaymentInstrumentLastUseDate(appABobPayId)); - assertEquals(15, PaymentPreferencesUtil.getPaymentInstrumentLastUseDate(appBCharliePayId)); + Assert.assertEquals(5, PaymentPreferencesUtil.getPaymentInstrumentUseCount(appAAlicePayId)); + Assert.assertEquals(10, PaymentPreferencesUtil.getPaymentInstrumentUseCount(appABobPayId)); + Assert.assertEquals( + 15, PaymentPreferencesUtil.getPaymentInstrumentUseCount(appBCharliePayId)); + Assert.assertEquals( + 5, PaymentPreferencesUtil.getPaymentInstrumentLastUseDate(appAAlicePayId)); + Assert.assertEquals( + 10, PaymentPreferencesUtil.getPaymentInstrumentLastUseDate(appABobPayId)); + Assert.assertEquals( + 15, PaymentPreferencesUtil.getPaymentInstrumentLastUseDate(appBCharliePayId)); // Sets Alice Pay use count and use date to 20. PaymentPreferencesUtil.setPaymentInstrumentUseCountForTest(appAAlicePayId, 20); PaymentPreferencesUtil.setPaymentInstrumentLastUseDate(appAAlicePayId, 20); - reTriggerUIAndWait("buy", getReadyToPay()); - clickInPaymentMethodAndWait(R.id.payments_section, getReadyForInput()); + mPaymentRequestTestRule.reTriggerUIAndWait("buy", mPaymentRequestTestRule.getReadyToPay()); + mPaymentRequestTestRule.clickInPaymentMethodAndWait( + R.id.payments_section, mPaymentRequestTestRule.getReadyForInput()); // Checks Alice Pay is listed at the first position. Checks Bob Pay is listed at the second // position together with Alice Pay since they come from the same app. - assertEquals(4, getNumberOfPaymentInstruments()); - assertEquals("https://alicepay.com", getPaymentInstrumentLabel(0)); - assertEquals("https://bobpay.com", getPaymentInstrumentLabel(1)); - assertEquals("https://charliepay.com", getPaymentInstrumentLabel(2)); - assertEquals( + Assert.assertEquals(4, mPaymentRequestTestRule.getNumberOfPaymentInstruments()); + Assert.assertEquals( + "https://alicepay.com", mPaymentRequestTestRule.getPaymentInstrumentLabel(0)); + Assert.assertEquals( + "https://bobpay.com", mPaymentRequestTestRule.getPaymentInstrumentLabel(1)); + Assert.assertEquals( + "https://charliepay.com", mPaymentRequestTestRule.getPaymentInstrumentLabel(2)); + Assert.assertEquals( "Visa\u0020\u0020\u2022\u2006\u2022\u2006\u2022\u2006\u2022\u20061111\nJon Doe", - getPaymentInstrumentLabel(3)); + mPaymentRequestTestRule.getPaymentInstrumentLabel(3)); - clickAndWait(R.id.button_primary, getDismissed()); + mPaymentRequestTestRule.clickAndWait( + R.id.button_primary, mPaymentRequestTestRule.getDismissed()); // Checks Alice Pay is selected as the default payment method. - expectResultContains(new String[] {"https://alicepay.com", "\"transaction\"", "1337"}); + mPaymentRequestTestRule.expectResultContains( + new String[] {"https://alicepay.com", "\"transaction\"", "1337"}); // Checks Alice Pay use count is increased by one after completing a payment request with // it. - assertEquals(21, PaymentPreferencesUtil.getPaymentInstrumentUseCount(appAAlicePayId)); - assertEquals(10, PaymentPreferencesUtil.getPaymentInstrumentUseCount(appABobPayId)); - assertEquals(15, PaymentPreferencesUtil.getPaymentInstrumentUseCount(appBCharliePayId)); - assertTrue(PaymentPreferencesUtil.getPaymentInstrumentLastUseDate(appAAlicePayId) > 20); - assertEquals(10, PaymentPreferencesUtil.getPaymentInstrumentLastUseDate(appABobPayId)); - assertEquals(15, PaymentPreferencesUtil.getPaymentInstrumentLastUseDate(appBCharliePayId)); + Assert.assertEquals( + 21, PaymentPreferencesUtil.getPaymentInstrumentUseCount(appAAlicePayId)); + Assert.assertEquals(10, PaymentPreferencesUtil.getPaymentInstrumentUseCount(appABobPayId)); + Assert.assertEquals( + 15, PaymentPreferencesUtil.getPaymentInstrumentUseCount(appBCharliePayId)); + Assert.assertTrue( + PaymentPreferencesUtil.getPaymentInstrumentLastUseDate(appAAlicePayId) > 20); + Assert.assertEquals( + 10, PaymentPreferencesUtil.getPaymentInstrumentLastUseDate(appABobPayId)); + Assert.assertEquals( + 15, PaymentPreferencesUtil.getPaymentInstrumentLastUseDate(appBCharliePayId)); } }
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestPhoneAndFreeShippingTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestPhoneAndFreeShippingTest.java index 6730a12..bd46925 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestPhoneAndFreeShippingTest.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestPhoneAndFreeShippingTest.java
@@ -7,12 +7,22 @@ import android.content.DialogInterface; import android.support.test.filters.MediumTest; +import org.junit.Assert; +import org.junit.Rule; +import org.junit.Test; +import org.junit.runner.RunWith; + import org.chromium.base.metrics.RecordHistogram; +import org.chromium.base.test.util.CommandLineFlags; import org.chromium.base.test.util.Feature; import org.chromium.chrome.R; +import org.chromium.chrome.browser.ChromeSwitches; import org.chromium.chrome.browser.autofill.AutofillTestHelper; import org.chromium.chrome.browser.autofill.PersonalDataManager.AutofillProfile; import org.chromium.chrome.browser.autofill.PersonalDataManager.CreditCard; +import org.chromium.chrome.browser.payments.PaymentRequestTestRule.MainActivityStartCallback; +import org.chromium.chrome.test.ChromeActivityTestRule; +import org.chromium.chrome.test.ChromeJUnit4ClassRunner; import java.util.concurrent.ExecutionException; import java.util.concurrent.TimeoutException; @@ -21,11 +31,15 @@ * A payment integration test for a merchant that requests a phone number and provides free shipping * regardless of address. */ -public class PaymentRequestPhoneAndFreeShippingTest extends PaymentRequestTestBase { - public PaymentRequestPhoneAndFreeShippingTest() { - // This merchant requests a phone number and provides free shipping worldwide. - super("payment_request_phone_and_free_shipping_test.html"); - } +@RunWith(ChromeJUnit4ClassRunner.class) +@CommandLineFlags.Add({ + ChromeSwitches.DISABLE_FIRST_RUN_EXPERIENCE, + ChromeActivityTestRule.DISABLE_NETWORK_PREDICTION_FLAG, +}) +public class PaymentRequestPhoneAndFreeShippingTest implements MainActivityStartCallback { + @Rule + public PaymentRequestTestRule mPaymentRequestTestRule = + new PaymentRequestTestRule("payment_request_phone_and_free_shipping_test.html", this); @Override public void onMainActivityStarted() @@ -41,16 +55,20 @@ } /** Submit the phone number and shipping address to the merchant when the user clicks "Pay." */ + @Test @MediumTest @Feature({"Payments"}) public void testPay() throws InterruptedException, ExecutionException, TimeoutException { - triggerUIAndWait(getReadyToPay()); - clickAndWait(R.id.button_primary, getReadyForUnmaskInput()); - setTextInCardUnmaskDialogAndWait(R.id.card_unmask_input, "123", getReadyToUnmask()); - clickCardUnmaskButtonAndWait(DialogInterface.BUTTON_POSITIVE, getDismissed()); - expectResultContains(new String[] {"+15555555555", "Jon Doe", "4111111111111111", "12", - "2050", "visa", "123", "Google", "340 Main St", "CA", "Los Angeles", "90291", "US", - "en", "freeShippingOption"}); + mPaymentRequestTestRule.triggerUIAndWait(mPaymentRequestTestRule.getReadyToPay()); + mPaymentRequestTestRule.clickAndWait( + R.id.button_primary, mPaymentRequestTestRule.getReadyForUnmaskInput()); + mPaymentRequestTestRule.setTextInCardUnmaskDialogAndWait( + R.id.card_unmask_input, "123", mPaymentRequestTestRule.getReadyToUnmask()); + mPaymentRequestTestRule.clickCardUnmaskButtonAndWait( + DialogInterface.BUTTON_POSITIVE, mPaymentRequestTestRule.getDismissed()); + mPaymentRequestTestRule.expectResultContains(new String[] {"+15555555555", "Jon Doe", + "4111111111111111", "12", "2050", "visa", "123", "Google", "340 Main St", "CA", + "Los Angeles", "90291", "US", "en", "freeShippingOption"}); } /** @@ -58,17 +76,23 @@ * results in the appropriate metric being logged in the PaymentRequest.RequestedInformation * histogram. */ + @Test @MediumTest @Feature({"Payments"}) - public void testRequestedInformationMetric() throws InterruptedException, ExecutionException, - TimeoutException { + public void testRequestedInformationMetric() + throws InterruptedException, ExecutionException, TimeoutException { // Start the Payment Request. - triggerUIAndWait(getReadyToPay()); + mPaymentRequestTestRule.triggerUIAndWait(mPaymentRequestTestRule.getReadyToPay()); // Make sure that only the appropriate enum value was logged. for (int i = 0; i < PaymentRequestMetrics.REQUESTED_INFORMATION_MAX; ++i) { - assertEquals((i == (PaymentRequestMetrics.REQUESTED_INFORMATION_PHONE - | PaymentRequestMetrics.REQUESTED_INFORMATION_SHIPPING) ? 1 : 0), + Assert.assertEquals( + (i + == (PaymentRequestMetrics.REQUESTED_INFORMATION_PHONE + | PaymentRequestMetrics + .REQUESTED_INFORMATION_SHIPPING) + ? 1 + : 0), RecordHistogram.getHistogramValueCountForTesting( "PaymentRequest.RequestedInformation", i)); }
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestPhoneTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestPhoneTest.java index 253ed69b4..70d10df7 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestPhoneTest.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestPhoneTest.java
@@ -4,13 +4,26 @@ package org.chromium.chrome.browser.payments; +import static org.chromium.chrome.browser.payments.PaymentRequestTestRule.HAVE_INSTRUMENTS; +import static org.chromium.chrome.browser.payments.PaymentRequestTestRule.IMMEDIATE_RESPONSE; + import android.support.test.filters.MediumTest; +import org.junit.Assert; +import org.junit.Rule; +import org.junit.Test; +import org.junit.runner.RunWith; + import org.chromium.base.metrics.RecordHistogram; +import org.chromium.base.test.util.CommandLineFlags; import org.chromium.base.test.util.Feature; import org.chromium.chrome.R; +import org.chromium.chrome.browser.ChromeSwitches; import org.chromium.chrome.browser.autofill.AutofillTestHelper; import org.chromium.chrome.browser.autofill.PersonalDataManager.AutofillProfile; +import org.chromium.chrome.browser.payments.PaymentRequestTestRule.MainActivityStartCallback; +import org.chromium.chrome.test.ChromeActivityTestRule; +import org.chromium.chrome.test.ChromeJUnit4ClassRunner; import java.util.concurrent.ExecutionException; import java.util.concurrent.TimeoutException; @@ -18,11 +31,15 @@ /** * A payment integration test for a merchant that requests phone number. */ -public class PaymentRequestPhoneTest extends PaymentRequestTestBase { - public PaymentRequestPhoneTest() { - // This merchant requests a phone number. - super("payment_request_phone_test.html"); - } +@RunWith(ChromeJUnit4ClassRunner.class) +@CommandLineFlags.Add({ + ChromeSwitches.DISABLE_FIRST_RUN_EXPERIENCE, + ChromeActivityTestRule.DISABLE_NETWORK_PREDICTION_FLAG, +}) +public class PaymentRequestPhoneTest implements MainActivityStartCallback { + @Rule + public PaymentRequestTestRule mPaymentRequestTestRule = + new PaymentRequestTestRule("payment_request_phone_test.html", this); @Override public void onMainActivityStarted() @@ -53,75 +70,93 @@ "Google", "340 Main St", "CA", "Los Angeles", "", "90291", "", "US", "555-555-5555", "jon.doe@google.com", "en-US")); - installPaymentApp(HAVE_INSTRUMENTS, IMMEDIATE_RESPONSE); + mPaymentRequestTestRule.installPaymentApp(HAVE_INSTRUMENTS, IMMEDIATE_RESPONSE); } /** Provide the existing valid phone number to the merchant. */ + @Test @MediumTest @Feature({"Payments"}) public void testPay() throws InterruptedException, ExecutionException, TimeoutException { - triggerUIAndWait(getReadyToPay()); - clickAndWait(R.id.button_primary, getDismissed()); - expectResultContains(new String[] {"+15555555555"}); + mPaymentRequestTestRule.triggerUIAndWait(mPaymentRequestTestRule.getReadyToPay()); + mPaymentRequestTestRule.clickAndWait( + R.id.button_primary, mPaymentRequestTestRule.getDismissed()); + mPaymentRequestTestRule.expectResultContains(new String[] {"+15555555555"}); } /** Attempt to add an invalid phone number and cancel the transaction. */ + @Test @MediumTest @Feature({"Payments"}) public void testAddInvalidPhoneAndCancel() throws InterruptedException, ExecutionException, TimeoutException { - triggerUIAndWait(getReadyToPay()); - clickInContactInfoAndWait(R.id.payments_section, getReadyForInput()); - clickInContactInfoAndWait(R.id.payments_add_option_button, getReadyToEdit()); - setTextInEditorAndWait(new String[] {"+++"}, getEditorTextUpdate()); - clickInEditorAndWait(R.id.payments_edit_done_button, getEditorValidationError()); - clickInEditorAndWait(R.id.payments_edit_cancel_button, getReadyToPay()); - clickAndWait(R.id.close_button, getDismissed()); - expectResultContains(new String[] {"Request cancelled"}); + mPaymentRequestTestRule.triggerUIAndWait(mPaymentRequestTestRule.getReadyToPay()); + mPaymentRequestTestRule.clickInContactInfoAndWait( + R.id.payments_section, mPaymentRequestTestRule.getReadyForInput()); + mPaymentRequestTestRule.clickInContactInfoAndWait( + R.id.payments_add_option_button, mPaymentRequestTestRule.getReadyToEdit()); + mPaymentRequestTestRule.setTextInEditorAndWait( + new String[] {"+++"}, mPaymentRequestTestRule.getEditorTextUpdate()); + mPaymentRequestTestRule.clickInEditorAndWait( + R.id.payments_edit_done_button, mPaymentRequestTestRule.getEditorValidationError()); + mPaymentRequestTestRule.clickInEditorAndWait( + R.id.payments_edit_cancel_button, mPaymentRequestTestRule.getReadyToPay()); + mPaymentRequestTestRule.clickAndWait( + R.id.close_button, mPaymentRequestTestRule.getDismissed()); + mPaymentRequestTestRule.expectResultContains(new String[] {"Request cancelled"}); } /** Add a new phone number and provide that to the merchant. */ + @Test @MediumTest @Feature({"Payments"}) public void testAddPhoneAndPay() throws InterruptedException, ExecutionException, TimeoutException { - triggerUIAndWait(getReadyToPay()); - clickInContactInfoAndWait(R.id.payments_section, getReadyForInput()); - clickInContactInfoAndWait(R.id.payments_add_option_button, getReadyToEdit()); - setTextInEditorAndWait(new String[] {"999-999-9999"}, getEditorTextUpdate()); - clickInEditorAndWait(R.id.payments_edit_done_button, getReadyToPay()); + mPaymentRequestTestRule.triggerUIAndWait(mPaymentRequestTestRule.getReadyToPay()); + mPaymentRequestTestRule.clickInContactInfoAndWait( + R.id.payments_section, mPaymentRequestTestRule.getReadyForInput()); + mPaymentRequestTestRule.clickInContactInfoAndWait( + R.id.payments_add_option_button, mPaymentRequestTestRule.getReadyToEdit()); + mPaymentRequestTestRule.setTextInEditorAndWait( + new String[] {"999-999-9999"}, mPaymentRequestTestRule.getEditorTextUpdate()); + mPaymentRequestTestRule.clickInEditorAndWait( + R.id.payments_edit_done_button, mPaymentRequestTestRule.getReadyToPay()); - clickAndWait(R.id.button_primary, getDismissed()); - expectResultContains(new String[] {"+19999999999"}); + mPaymentRequestTestRule.clickAndWait( + R.id.button_primary, mPaymentRequestTestRule.getDismissed()); + mPaymentRequestTestRule.expectResultContains(new String[] {"+19999999999"}); } /** * Makes sure that suggestions that are equal to or subsets of other suggestions are not shown * to the user. */ + @Test @MediumTest @Feature({"Payments"}) public void testSuggestionsDeduped() throws InterruptedException, ExecutionException, TimeoutException { - triggerUIAndWait(getReadyToPay()); - clickInContactInfoAndWait(R.id.payments_section, getReadyForInput()); - assertEquals(1, getNumberOfContactDetailSuggestions()); + mPaymentRequestTestRule.triggerUIAndWait(mPaymentRequestTestRule.getReadyToPay()); + mPaymentRequestTestRule.clickInContactInfoAndWait( + R.id.payments_section, mPaymentRequestTestRule.getReadyForInput()); + Assert.assertEquals(1, mPaymentRequestTestRule.getNumberOfContactDetailSuggestions()); } /** * Test that starting a payment request that requires only the user's phone number results in * the appropriate metric being logged in the PaymentRequest.RequestedInformation histogram. */ + @Test @MediumTest @Feature({"Payments"}) - public void testRequestedInformationMetric() throws InterruptedException, ExecutionException, - TimeoutException { + public void testRequestedInformationMetric() + throws InterruptedException, ExecutionException, TimeoutException { // Start the Payment Request. - triggerUIAndWait(getReadyToPay()); + mPaymentRequestTestRule.triggerUIAndWait(mPaymentRequestTestRule.getReadyToPay()); // Make sure that only the appropriate enum value was logged. for (int i = 0; i < PaymentRequestMetrics.REQUESTED_INFORMATION_MAX; ++i) { - assertEquals((i == PaymentRequestMetrics.REQUESTED_INFORMATION_PHONE ? 1 : 0), + Assert.assertEquals((i == PaymentRequestMetrics.REQUESTED_INFORMATION_PHONE ? 1 : 0), RecordHistogram.getHistogramValueCountForTesting( "PaymentRequest.RequestedInformation", i)); }
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestRemoveBillingAddressTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestRemoveBillingAddressTest.java index 1d234c5..d7bf7f5 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestRemoveBillingAddressTest.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestRemoveBillingAddressTest.java
@@ -4,14 +4,27 @@ package org.chromium.chrome.browser.payments; +import static org.chromium.chrome.browser.payments.PaymentRequestTestRule.DECEMBER; +import static org.chromium.chrome.browser.payments.PaymentRequestTestRule.FIRST_BILLING_ADDRESS; +import static org.chromium.chrome.browser.payments.PaymentRequestTestRule.NEXT_YEAR; + import android.content.DialogInterface; import android.support.test.filters.MediumTest; +import org.junit.Rule; +import org.junit.Test; +import org.junit.runner.RunWith; + +import org.chromium.base.test.util.CommandLineFlags; import org.chromium.base.test.util.Feature; import org.chromium.chrome.R; +import org.chromium.chrome.browser.ChromeSwitches; import org.chromium.chrome.browser.autofill.AutofillTestHelper; import org.chromium.chrome.browser.autofill.PersonalDataManager.AutofillProfile; import org.chromium.chrome.browser.autofill.PersonalDataManager.CreditCard; +import org.chromium.chrome.browser.payments.PaymentRequestTestRule.MainActivityStartCallback; +import org.chromium.chrome.test.ChromeActivityTestRule; +import org.chromium.chrome.test.ChromeJUnit4ClassRunner; import java.util.concurrent.ExecutionException; import java.util.concurrent.TimeoutException; @@ -19,10 +32,15 @@ /** * A payment integration test for removing a billing address that is associated with a credit card. */ -public class PaymentRequestRemoveBillingAddressTest extends PaymentRequestTestBase { - public PaymentRequestRemoveBillingAddressTest() { - super("payment_request_no_shipping_test.html"); - } +@RunWith(ChromeJUnit4ClassRunner.class) +@CommandLineFlags.Add({ + ChromeSwitches.DISABLE_FIRST_RUN_EXPERIENCE, + ChromeActivityTestRule.DISABLE_NETWORK_PREDICTION_FLAG, +}) +public class PaymentRequestRemoveBillingAddressTest implements MainActivityStartCallback { + @Rule + public PaymentRequestTestRule mPaymentRequestTestRule = + new PaymentRequestTestRule("payment_request_no_shipping_test.html", this); @Override public void onMainActivityStarted() @@ -44,36 +62,44 @@ * The billing address for the credit card has been removed. Using this card should bring up an * editor that requires selecting a new billing address. */ + @Test @MediumTest @Feature({"Payments"}) public void testPayWithCard() throws InterruptedException, ExecutionException, TimeoutException { - triggerUIAndWait(getReadyForInput()); + mPaymentRequestTestRule.triggerUIAndWait(mPaymentRequestTestRule.getReadyForInput()); // Expand the payment section. - clickInPaymentMethodAndWait(R.id.payments_section, getReadyForInput()); + mPaymentRequestTestRule.clickInPaymentMethodAndWait( + R.id.payments_section, mPaymentRequestTestRule.getReadyForInput()); // Selecting the credit card should bring up the editor. - clickInPaymentMethodAndWait(R.id.payments_first_radio_button, getReadyToEdit()); + mPaymentRequestTestRule.clickInPaymentMethodAndWait( + R.id.payments_first_radio_button, mPaymentRequestTestRule.getReadyToEdit()); // Tapping "save" in the editor should trigger a validation error. - clickInCardEditorAndWait(R.id.payments_edit_done_button, getEditorValidationError()); + mPaymentRequestTestRule.clickInCardEditorAndWait( + R.id.payments_edit_done_button, mPaymentRequestTestRule.getEditorValidationError()); // Fix the validation error by selecting a billing address. - setSpinnerSelectionsInCardEditorAndWait( + mPaymentRequestTestRule.setSpinnerSelectionsInCardEditorAndWait( new int[] {DECEMBER, NEXT_YEAR, FIRST_BILLING_ADDRESS}, - getBillingAddressChangeProcessed()); + mPaymentRequestTestRule.getBillingAddressChangeProcessed()); // Tapping "save" in the editor now should close the editor dialog and enable the "pay" // button. - clickInCardEditorAndWait(R.id.payments_edit_done_button, getReadyToPay()); + mPaymentRequestTestRule.clickInCardEditorAndWait( + R.id.payments_edit_done_button, mPaymentRequestTestRule.getReadyToPay()); // Pay with this card. - clickAndWait(R.id.button_primary, getReadyForUnmaskInput()); - setTextInCardUnmaskDialogAndWait(R.id.card_unmask_input, "123", getReadyToUnmask()); - clickCardUnmaskButtonAndWait(DialogInterface.BUTTON_POSITIVE, getDismissed()); - expectResultContains(new String[] {"4111111111111111", "Alice", "12", "123", "Jane Smith", - "Google", "1600 Amphitheatre Pkwy", "CA", "Mountain View", "94043", "US", - "+15555555555", "en-US"}); + mPaymentRequestTestRule.clickAndWait( + R.id.button_primary, mPaymentRequestTestRule.getReadyForUnmaskInput()); + mPaymentRequestTestRule.setTextInCardUnmaskDialogAndWait( + R.id.card_unmask_input, "123", mPaymentRequestTestRule.getReadyToUnmask()); + mPaymentRequestTestRule.clickCardUnmaskButtonAndWait( + DialogInterface.BUTTON_POSITIVE, mPaymentRequestTestRule.getDismissed()); + mPaymentRequestTestRule.expectResultContains(new String[] {"4111111111111111", "Alice", + "12", "123", "Jane Smith", "Google", "1600 Amphitheatre Pkwy", "CA", + "Mountain View", "94043", "US", "+15555555555", "en-US"}); } }
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestServerCardTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestServerCardTest.java index 34ce490..5ac47af 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestServerCardTest.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestServerCardTest.java
@@ -7,11 +7,20 @@ import android.content.DialogInterface; import android.support.test.filters.MediumTest; +import org.junit.Rule; +import org.junit.Test; +import org.junit.runner.RunWith; + +import org.chromium.base.test.util.CommandLineFlags; import org.chromium.base.test.util.Feature; import org.chromium.chrome.R; +import org.chromium.chrome.browser.ChromeSwitches; import org.chromium.chrome.browser.autofill.AutofillTestHelper; import org.chromium.chrome.browser.autofill.PersonalDataManager.AutofillProfile; import org.chromium.chrome.browser.autofill.PersonalDataManager.CreditCard; +import org.chromium.chrome.browser.payments.PaymentRequestTestRule.MainActivityStartCallback; +import org.chromium.chrome.test.ChromeActivityTestRule; +import org.chromium.chrome.test.ChromeJUnit4ClassRunner; import java.util.concurrent.ExecutionException; import java.util.concurrent.TimeoutException; @@ -19,10 +28,15 @@ /** * A test for using a server card in payments UI. */ -public class PaymentRequestServerCardTest extends PaymentRequestTestBase { - public PaymentRequestServerCardTest() { - super("payment_request_no_shipping_test.html"); - } +@RunWith(ChromeJUnit4ClassRunner.class) +@CommandLineFlags.Add({ + ChromeSwitches.DISABLE_FIRST_RUN_EXPERIENCE, + ChromeActivityTestRule.DISABLE_NETWORK_PREDICTION_FLAG, +}) +public class PaymentRequestServerCardTest implements MainActivityStartCallback { + @Rule + public PaymentRequestTestRule mPaymentRequestTestRule = + new PaymentRequestTestRule("payment_request_no_shipping_test.html", this); @Override public void onMainActivityStarted() @@ -38,14 +52,18 @@ } /** Click [PAY] and dismiss the card unmask dialog. */ + @Test @MediumTest @Feature({"Payments"}) - public void testPayAndDontUnmask() throws InterruptedException, ExecutionException, - TimeoutException { - triggerUIAndWait(getReadyToPay()); - clickAndWait(R.id.button_primary, getReadyForUnmaskInput()); - clickCardUnmaskButtonAndWait(DialogInterface.BUTTON_NEGATIVE, getReadyToPay()); - clickAndWait(R.id.close_button, getDismissed()); - expectResultContains(new String[] {"Request cancelled"}); + public void testPayAndDontUnmask() + throws InterruptedException, ExecutionException, TimeoutException { + mPaymentRequestTestRule.triggerUIAndWait(mPaymentRequestTestRule.getReadyToPay()); + mPaymentRequestTestRule.clickAndWait( + R.id.button_primary, mPaymentRequestTestRule.getReadyForUnmaskInput()); + mPaymentRequestTestRule.clickCardUnmaskButtonAndWait( + DialogInterface.BUTTON_NEGATIVE, mPaymentRequestTestRule.getReadyToPay()); + mPaymentRequestTestRule.clickAndWait( + R.id.close_button, mPaymentRequestTestRule.getDismissed()); + mPaymentRequestTestRule.expectResultContains(new String[] {"Request cancelled"}); } }
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestServiceWorkerPaymentAppTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestServiceWorkerPaymentAppTest.java index 9f4e268d..dbba560a 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestServiceWorkerPaymentAppTest.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestServiceWorkerPaymentAppTest.java
@@ -6,7 +6,15 @@ import android.support.test.filters.MediumTest; +import org.junit.Rule; +import org.junit.Test; +import org.junit.runner.RunWith; + +import org.chromium.base.test.util.CommandLineFlags; import org.chromium.base.test.util.Feature; +import org.chromium.chrome.browser.ChromeSwitches; +import org.chromium.chrome.test.ChromeActivityTestRule; +import org.chromium.chrome.test.ChromeJUnit4ClassRunner; import org.chromium.content_public.browser.WebContents; import java.util.ArrayList; @@ -20,7 +28,16 @@ /** * A payment integration test for service worker based payment apps. */ -public class PaymentRequestServiceWorkerPaymentAppTest extends PaymentRequestTestBase { +@RunWith(ChromeJUnit4ClassRunner.class) +@CommandLineFlags.Add({ + ChromeSwitches.DISABLE_FIRST_RUN_EXPERIENCE, + ChromeActivityTestRule.DISABLE_NETWORK_PREDICTION_FLAG, +}) +public class PaymentRequestServiceWorkerPaymentAppTest { + @Rule + public PaymentRequestTestRule mPaymentRequestTestRule = + new PaymentRequestTestRule("payment_request_bobpay_test.html"); + /** Flag for installing a service worker payment app without any payment options. */ private static final int NO_OPTIONS = 0; @@ -30,10 +47,6 @@ /** Flag for installing a service worker payment app with two options. */ private static final int TWO_OPTIONS = 2; - public PaymentRequestServiceWorkerPaymentAppTest() { - super("payment_request_bobpay_test.html"); - } - /** * Installs a mock service worker based payment app for testing. * @@ -71,36 +84,32 @@ }); } - @Override - public void onMainActivityStarted() throws InterruptedException, ExecutionException, - TimeoutException {} - + @Test @MediumTest @Feature({"Payments"}) - public void testNoOptions() throws InterruptedException, ExecutionException, - TimeoutException { + public void testNoOptions() throws InterruptedException, ExecutionException, TimeoutException { installMockServiceWorkerPaymentApp(NO_OPTIONS); - openPageAndClickBuyAndWait(getShowFailed()); - expectResultContains( - new String[]{"show() rejected", "The payment method is not supported"}); + mPaymentRequestTestRule.openPageAndClickBuyAndWait(mPaymentRequestTestRule.getShowFailed()); + mPaymentRequestTestRule.expectResultContains( + new String[] {"show() rejected", "The payment method is not supported"}); } + @Test @MediumTest @Feature({"Payments"}) - public void testOneOption() throws InterruptedException, ExecutionException, - TimeoutException { + public void testOneOption() throws InterruptedException, ExecutionException, TimeoutException { installMockServiceWorkerPaymentApp(ONE_OPTION); - triggerUIAndWait(getReadyForInput()); + mPaymentRequestTestRule.triggerUIAndWait(mPaymentRequestTestRule.getReadyForInput()); // TODO(tommyt): crbug.com/669876. Expand this test as we implement more // service worker based payment app functionality. } + @Test @MediumTest @Feature({"Payments"}) - public void testTwoOptions() throws InterruptedException, ExecutionException, - TimeoutException { + public void testTwoOptions() throws InterruptedException, ExecutionException, TimeoutException { installMockServiceWorkerPaymentApp(TWO_OPTIONS); - triggerUIAndWait(getReadyForInput()); + mPaymentRequestTestRule.triggerUIAndWait(mPaymentRequestTestRule.getReadyForInput()); // TODO(tommyt): crbug.com/669876. Expand this test as we implement more // service worker based payment app functionality. }
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestShippingAddressChangeTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestShippingAddressChangeTest.java index e5bbe2b24..e99e614 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestShippingAddressChangeTest.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestShippingAddressChangeTest.java
@@ -6,11 +6,20 @@ import android.support.test.filters.MediumTest; +import org.junit.Rule; +import org.junit.Test; +import org.junit.runner.RunWith; + +import org.chromium.base.test.util.CommandLineFlags; import org.chromium.base.test.util.Feature; import org.chromium.chrome.R; +import org.chromium.chrome.browser.ChromeSwitches; import org.chromium.chrome.browser.autofill.AutofillTestHelper; import org.chromium.chrome.browser.autofill.PersonalDataManager.AutofillProfile; import org.chromium.chrome.browser.autofill.PersonalDataManager.CreditCard; +import org.chromium.chrome.browser.payments.PaymentRequestTestRule.MainActivityStartCallback; +import org.chromium.chrome.test.ChromeActivityTestRule; +import org.chromium.chrome.test.ChromeJUnit4ClassRunner; import java.util.concurrent.ExecutionException; import java.util.concurrent.TimeoutException; @@ -18,13 +27,15 @@ /** * A payment integration test for a merchant that requires shipping address to calculate shipping. */ -public class PaymentRequestShippingAddressChangeTest extends PaymentRequestTestBase { - public PaymentRequestShippingAddressChangeTest() { - // This merchant requests the shipping address first before providing any shipping options. - // The result printed from this site is the shipping address change, not the Payment - // Response. - super("payment_request_shipping_address_change_test.html"); - } +@RunWith(ChromeJUnit4ClassRunner.class) +@CommandLineFlags.Add({ + ChromeSwitches.DISABLE_FIRST_RUN_EXPERIENCE, + ChromeActivityTestRule.DISABLE_NETWORK_PREDICTION_FLAG, +}) +public class PaymentRequestShippingAddressChangeTest implements MainActivityStartCallback { + @Rule + public PaymentRequestTestRule mPaymentRequestTestRule = + new PaymentRequestTestRule("payment_request_shipping_address_change_test.html", this); @Override public void onMainActivityStarted() @@ -43,18 +54,22 @@ * Tests the format of the shipping address that is sent to the merchant when the user changes * the shipping address selection. */ + @Test @MediumTest @Feature({"Payments"}) public void testShippingAddressChangeFormat() throws InterruptedException, ExecutionException, TimeoutException { // Select a shipping address and cancel out. - triggerUIAndWait(getReadyForInput()); - clickInShippingSummaryAndWait(R.id.payments_section, getReadyForInput()); - clickOnShippingAddressSuggestionOptionAndWait(0, getReadyForInput()); - clickAndWait(R.id.close_button, getDismissed()); + mPaymentRequestTestRule.triggerUIAndWait(mPaymentRequestTestRule.getReadyForInput()); + mPaymentRequestTestRule.clickInShippingSummaryAndWait( + R.id.payments_section, mPaymentRequestTestRule.getReadyForInput()); + mPaymentRequestTestRule.clickOnShippingAddressSuggestionOptionAndWait( + 0, mPaymentRequestTestRule.getReadyForInput()); + mPaymentRequestTestRule.clickAndWait( + R.id.close_button, mPaymentRequestTestRule.getDismissed()); // The phone number should be formatted to the internation format. - expectResultContains(new String[] {"Jon Doe", "Google", "340 Main St", "CA", "Los Angeles", - "90291", "+16502530000", "US"}); + mPaymentRequestTestRule.expectResultContains(new String[] {"Jon Doe", "Google", + "340 Main St", "CA", "Los Angeles", "90291", "+16502530000", "US"}); } }
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestShippingAddressTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestShippingAddressTest.java index e044e11..396761ca 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestShippingAddressTest.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestShippingAddressTest.java
@@ -6,11 +6,21 @@ import android.support.test.filters.MediumTest; +import org.junit.Assert; +import org.junit.Rule; +import org.junit.Test; +import org.junit.runner.RunWith; + +import org.chromium.base.test.util.CommandLineFlags; import org.chromium.base.test.util.Feature; import org.chromium.chrome.R; +import org.chromium.chrome.browser.ChromeSwitches; import org.chromium.chrome.browser.autofill.AutofillTestHelper; import org.chromium.chrome.browser.autofill.PersonalDataManager.AutofillProfile; import org.chromium.chrome.browser.autofill.PersonalDataManager.CreditCard; +import org.chromium.chrome.browser.payments.PaymentRequestTestRule.MainActivityStartCallback; +import org.chromium.chrome.test.ChromeActivityTestRule; +import org.chromium.chrome.test.ChromeJUnit4ClassRunner; import java.util.concurrent.ExecutionException; import java.util.concurrent.TimeoutException; @@ -18,10 +28,15 @@ /** * A payment integration test for shipping address labels. */ -public class PaymentRequestShippingAddressTest extends PaymentRequestTestBase { - public PaymentRequestShippingAddressTest() { - super("payment_request_free_shipping_test.html"); - } +@RunWith(ChromeJUnit4ClassRunner.class) +@CommandLineFlags.Add({ + ChromeSwitches.DISABLE_FIRST_RUN_EXPERIENCE, + ChromeActivityTestRule.DISABLE_NETWORK_PREDICTION_FLAG, +}) +public class PaymentRequestShippingAddressTest implements MainActivityStartCallback { + @Rule + public PaymentRequestTestRule mPaymentRequestTestRule = + new PaymentRequestTestRule("payment_request_free_shipping_test.html", this); @Override public void onMainActivityStarted() @@ -46,152 +61,187 @@ } /** Verifies that the shipping address format in bottomsheet mode is as expected. */ + @Test @MediumTest @Feature({"Payments"}) public void testShippingAddressFormat_BottomSheet() throws InterruptedException, ExecutionException, TimeoutException { - triggerUIAndWait(getReadyToPay()); + mPaymentRequestTestRule.triggerUIAndWait(mPaymentRequestTestRule.getReadyToPay()); // Make sure that the shipping label on the bottomsheet does not include the country. - assertTrue(getShippingAddressOptionRowAtIndex(0).getLabelText().toString().equals( - "Jon Doe\nGoogle, 340 Main St, Los Angeles, CA 90291\n555-555-5555")); + Assert.assertTrue(mPaymentRequestTestRule.getShippingAddressOptionRowAtIndex(0) + .getLabelText().toString().equals( + "Jon Doe\nGoogle, 340 Main St, Los Angeles, CA 90291\n555-555-5555")); } /** Verifies that the shipping address format in fullsheet mode is as expected. */ + @Test @MediumTest @Feature({"Payments"}) public void testShippingAddressFormat_FullSheet() throws InterruptedException, ExecutionException, TimeoutException { - triggerUIAndWait(getReadyToPay()); + mPaymentRequestTestRule.triggerUIAndWait(mPaymentRequestTestRule.getReadyToPay()); // Focus on a section other that shipping addresses to enter fullsheet mode. - clickInShippingSummaryAndWait(R.id.payments_section, getReadyForInput()); + mPaymentRequestTestRule.clickInShippingSummaryAndWait( + R.id.payments_section, mPaymentRequestTestRule.getReadyForInput()); // Make sure that the shipping label on the fullsheet does not include the country. - assertTrue(getShippingAddressOptionRowAtIndex(0).getLabelText().toString().equals( - "Jon Doe\nGoogle, 340 Main St, Los Angeles, CA 90291\n555-555-5555")); + Assert.assertTrue(mPaymentRequestTestRule.getShippingAddressOptionRowAtIndex(0) + .getLabelText().toString().equals( + "Jon Doe\nGoogle, 340 Main St, Los Angeles, CA 90291\n555-555-5555")); } /** Verifies that the shipping address format in fullsheet mode is as expected. */ + @Test @MediumTest @Feature({"Payments"}) public void testShippingAddressFormat_Expanded() throws InterruptedException, ExecutionException, TimeoutException { - triggerUIAndWait(getReadyToPay()); + mPaymentRequestTestRule.triggerUIAndWait(mPaymentRequestTestRule.getReadyToPay()); // Focus on the shipping addresses section to enter expanded mode. - clickInShippingAddressAndWait(R.id.payments_section, getReadyForInput()); + mPaymentRequestTestRule.clickInShippingAddressAndWait( + R.id.payments_section, mPaymentRequestTestRule.getReadyForInput()); // Make sure that the shipping label in expanded mode includes the country. - assertTrue(getShippingAddressOptionRowAtIndex(0).getLabelText().toString().equals( - "Jon Doe\n" - + "Google, 340 Main St, Los Angeles, CA 90291, United States\n" - + "555-555-5555")); + Assert.assertTrue( + mPaymentRequestTestRule.getShippingAddressOptionRowAtIndex(0) + .getLabelText() + .toString() + .equals("Jon Doe\n" + + "Google, 340 Main St, Los Angeles, CA 90291, United States\n" + + "555-555-5555")); // Make sure that the second profile's shipping label also includes the country. - assertTrue(getShippingAddressOptionRowAtIndex(1).getLabelText().toString().equals( - "Fred Doe\n" - + "Google, 340 Main St, Los Angeles, CA 90291, United States\n" - + "555-555-5555")); + Assert.assertTrue( + mPaymentRequestTestRule.getShippingAddressOptionRowAtIndex(1) + .getLabelText() + .toString() + .equals("Fred Doe\n" + + "Google, 340 Main St, Los Angeles, CA 90291, United States\n" + + "555-555-5555")); } /** Verifies that the shipping address format of a new address is as expected. */ + @Test @MediumTest @Feature({"Payments"}) public void testShippingAddressFormat_NewAddress() throws InterruptedException, ExecutionException, TimeoutException { - triggerUIAndWait(getReadyToPay()); + mPaymentRequestTestRule.triggerUIAndWait(mPaymentRequestTestRule.getReadyToPay()); // Add a shipping address. - clickInShippingSummaryAndWait(R.id.payments_section, getReadyForInput()); - clickInShippingAddressAndWait(R.id.payments_add_option_button, getReadyToEdit()); - setTextInEditorAndWait(new String[] {"Seb Doe", "Google", "340 Main St", "Los Angeles", - "CA", "90291", "650-253-0000"}, - getEditorTextUpdate()); - clickInEditorAndWait(R.id.payments_edit_done_button, getReadyToPay()); + mPaymentRequestTestRule.clickInShippingSummaryAndWait( + R.id.payments_section, mPaymentRequestTestRule.getReadyForInput()); + mPaymentRequestTestRule.clickInShippingAddressAndWait( + R.id.payments_add_option_button, mPaymentRequestTestRule.getReadyToEdit()); + mPaymentRequestTestRule.setTextInEditorAndWait( + new String[] {"Seb Doe", "Google", "340 Main St", "Los Angeles", "CA", "90291", + "650-253-0000"}, + mPaymentRequestTestRule.getEditorTextUpdate()); + mPaymentRequestTestRule.clickInEditorAndWait( + R.id.payments_edit_done_button, mPaymentRequestTestRule.getReadyToPay()); // Make sure that the shipping label does not include the country. - assertTrue(getShippingAddressOptionRowAtIndex(0).getLabelText().toString().equals( - "Seb Doe\nGoogle, 340 Main St, Los Angeles, CA 90291\n+1 650-253-0000")); + Assert.assertTrue(mPaymentRequestTestRule.getShippingAddressOptionRowAtIndex(0) + .getLabelText().toString().equals( + "Seb Doe\nGoogle, 340 Main St, Los Angeles, CA 90291\n+1 650-253-0000")); } /** * Test that going into the editor and clicking 'CANCEL' button to cancel editor will leave the * row checked. */ + @Test @MediumTest @Feature({"Payments"}) public void testEditShippingAddressAndCancelEditorShouldKeepAddressSelected() throws InterruptedException, ExecutionException, TimeoutException { - triggerUIAndWait(getReadyToPay()); - clickInShippingSummaryAndWait(R.id.payments_section, getReadyForInput()); - expectShippingAddressRowIsSelected(0); - clickInShippingAddressAndWait(R.id.payments_open_editor_pencil_button, getReadyToEdit()); + mPaymentRequestTestRule.triggerUIAndWait(mPaymentRequestTestRule.getReadyToPay()); + mPaymentRequestTestRule.clickInShippingSummaryAndWait( + R.id.payments_section, mPaymentRequestTestRule.getReadyForInput()); + mPaymentRequestTestRule.expectShippingAddressRowIsSelected(0); + mPaymentRequestTestRule.clickInShippingAddressAndWait( + R.id.payments_open_editor_pencil_button, mPaymentRequestTestRule.getReadyToEdit()); // Cancel the editor by clicking 'CANCEL' button in the editor view. - clickInEditorAndWait(R.id.payments_edit_cancel_button, getReadyToPay()); + mPaymentRequestTestRule.clickInEditorAndWait( + R.id.payments_edit_cancel_button, mPaymentRequestTestRule.getReadyToPay()); // Expect the row to still be selected in the Shipping Address section. - expectShippingAddressRowIsSelected(0); + mPaymentRequestTestRule.expectShippingAddressRowIsSelected(0); } /** * Test that going into the editor and clicking Android back button to cancel editor will leave * the row checked. */ + @Test @MediumTest @Feature({"Payments"}) public void testEditShippingAddressAndClickAndroidBackButtonShouldKeepAddressSelected() throws InterruptedException, ExecutionException, TimeoutException { - triggerUIAndWait(getReadyToPay()); - clickInShippingSummaryAndWait(R.id.payments_section, getReadyForInput()); - expectShippingAddressRowIsSelected(0); - clickInShippingAddressAndWait(R.id.payments_open_editor_pencil_button, getReadyToEdit()); + mPaymentRequestTestRule.triggerUIAndWait(mPaymentRequestTestRule.getReadyToPay()); + mPaymentRequestTestRule.clickInShippingSummaryAndWait( + R.id.payments_section, mPaymentRequestTestRule.getReadyForInput()); + mPaymentRequestTestRule.expectShippingAddressRowIsSelected(0); + mPaymentRequestTestRule.clickInShippingAddressAndWait( + R.id.payments_open_editor_pencil_button, mPaymentRequestTestRule.getReadyToEdit()); // Cancel the editor by clicking Android back button. - clickAndroidBackButtonInEditorAndWait(getReadyToPay()); + mPaymentRequestTestRule.clickAndroidBackButtonInEditorAndWait( + mPaymentRequestTestRule.getReadyToPay()); // Expect the row to still be selected in the Shipping Address section. - expectShippingAddressRowIsSelected(0); + mPaymentRequestTestRule.expectShippingAddressRowIsSelected(0); } /** * Test that going into the "add" flow and clicking 'CANCEL' button to cancel editor will * leave the existing row checked. */ + @Test @MediumTest @Feature({"Payments"}) public void testAddShippingAddressAndCancelEditorShouldKeepAddressSelected() throws InterruptedException, ExecutionException, TimeoutException { - triggerUIAndWait(getReadyToPay()); - clickInShippingSummaryAndWait(R.id.payments_section, getReadyForInput()); - expectShippingAddressRowIsSelected(0); - clickInShippingAddressAndWait(R.id.payments_add_option_button, getReadyToEdit()); + mPaymentRequestTestRule.triggerUIAndWait(mPaymentRequestTestRule.getReadyToPay()); + mPaymentRequestTestRule.clickInShippingSummaryAndWait( + R.id.payments_section, mPaymentRequestTestRule.getReadyForInput()); + mPaymentRequestTestRule.expectShippingAddressRowIsSelected(0); + mPaymentRequestTestRule.clickInShippingAddressAndWait( + R.id.payments_add_option_button, mPaymentRequestTestRule.getReadyToEdit()); // Cancel the editor by clicking 'CANCEL' button in the editor view. - clickInEditorAndWait(R.id.payments_edit_cancel_button, getReadyToPay()); + mPaymentRequestTestRule.clickInEditorAndWait( + R.id.payments_edit_cancel_button, mPaymentRequestTestRule.getReadyToPay()); // Expect the existing row to still be selected in the Shipping Address section. - expectShippingAddressRowIsSelected(0); + mPaymentRequestTestRule.expectShippingAddressRowIsSelected(0); } /** * Test that going into the "add" flow and clicking Android back button to cancel editor will * leave the existing row checked. */ + @Test @MediumTest @Feature({"Payments"}) public void testAddShippingAddressAndClickAndroidBackButtonShouldKeepAddressSelected() throws InterruptedException, ExecutionException, TimeoutException { - triggerUIAndWait(getReadyToPay()); - clickInShippingSummaryAndWait(R.id.payments_section, getReadyForInput()); - expectShippingAddressRowIsSelected(0); - clickInShippingAddressAndWait(R.id.payments_add_option_button, getReadyToEdit()); + mPaymentRequestTestRule.triggerUIAndWait(mPaymentRequestTestRule.getReadyToPay()); + mPaymentRequestTestRule.clickInShippingSummaryAndWait( + R.id.payments_section, mPaymentRequestTestRule.getReadyForInput()); + mPaymentRequestTestRule.expectShippingAddressRowIsSelected(0); + mPaymentRequestTestRule.clickInShippingAddressAndWait( + R.id.payments_add_option_button, mPaymentRequestTestRule.getReadyToEdit()); // Cancel the editor by clicking Android back button. - clickAndroidBackButtonInEditorAndWait(getReadyToPay()); + mPaymentRequestTestRule.clickAndroidBackButtonInEditorAndWait( + mPaymentRequestTestRule.getReadyToPay()); // Expect the existing row to still be selected in the Shipping Address section. - expectShippingAddressRowIsSelected(0); + mPaymentRequestTestRule.expectShippingAddressRowIsSelected(0); } }
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestShowTwiceTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestShowTwiceTest.java index db168cc47..c1470c1 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestShowTwiceTest.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestShowTwiceTest.java
@@ -6,12 +6,22 @@ import android.support.test.filters.MediumTest; +import org.junit.Assert; +import org.junit.Rule; +import org.junit.Test; +import org.junit.runner.RunWith; + import org.chromium.base.metrics.RecordHistogram; +import org.chromium.base.test.util.CommandLineFlags; import org.chromium.base.test.util.Feature; import org.chromium.chrome.R; +import org.chromium.chrome.browser.ChromeSwitches; import org.chromium.chrome.browser.autofill.AutofillTestHelper; import org.chromium.chrome.browser.autofill.PersonalDataManager.AutofillProfile; import org.chromium.chrome.browser.autofill.PersonalDataManager.CreditCard; +import org.chromium.chrome.browser.payments.PaymentRequestTestRule.MainActivityStartCallback; +import org.chromium.chrome.test.ChromeActivityTestRule; +import org.chromium.chrome.test.ChromeJUnit4ClassRunner; import java.util.concurrent.ExecutionException; import java.util.concurrent.TimeoutException; @@ -19,10 +29,15 @@ /** * A payment integration test for a merchant that calls show() twice. */ -public class PaymentRequestShowTwiceTest extends PaymentRequestTestBase { - public PaymentRequestShowTwiceTest() { - super("payment_request_show_twice_test.html"); - } +@RunWith(ChromeJUnit4ClassRunner.class) +@CommandLineFlags.Add({ + ChromeSwitches.DISABLE_FIRST_RUN_EXPERIENCE, + ChromeActivityTestRule.DISABLE_NETWORK_PREDICTION_FLAG, +}) +public class PaymentRequestShowTwiceTest implements MainActivityStartCallback { + @Rule + public PaymentRequestTestRule mPaymentRequestTestRule = + new PaymentRequestTestRule("payment_request_show_twice_test.html", this); @Override public void onMainActivityStarted() @@ -36,22 +51,25 @@ billingAddressId, "" /* serverId */)); } + @Test @MediumTest @Feature({"Payments"}) public void testSecondShowRequestCancelled() throws InterruptedException, ExecutionException, TimeoutException { - triggerUIAndWait(getReadyToPay()); - expectResultContains(new String[] {"Second request: AbortError: Request cancelled"}); + mPaymentRequestTestRule.triggerUIAndWait(mPaymentRequestTestRule.getReadyToPay()); + mPaymentRequestTestRule.expectResultContains( + new String[] {"Second request: AbortError: Request cancelled"}); // The web payments UI was not aborted. - assertOnlySpecificAbortMetricLogged(-1 /* none */); + mPaymentRequestTestRule.assertOnlySpecificAbortMetricLogged(-1 /* none */); // The UI was never shown due to another web payments UI already showing. - assertEquals(1, + Assert.assertEquals(1, RecordHistogram.getHistogramValueCountForTesting( "PaymentRequest.CheckoutFunnel.NoShow", PaymentRequestMetrics.NO_SHOW_CONCURRENT_REQUESTS)); - clickAndWait(R.id.close_button, getDismissed()); + mPaymentRequestTestRule.clickAndWait( + R.id.close_button, mPaymentRequestTestRule.getDismissed()); } }
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestTabTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestTabTest.java index 3250176..6e292dd 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestTabTest.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestTabTest.java
@@ -6,16 +6,26 @@ import android.support.test.filters.MediumTest; +import org.junit.Assert; +import org.junit.Rule; +import org.junit.Test; +import org.junit.runner.RunWith; + import org.chromium.base.ThreadUtils; +import org.chromium.base.test.util.CommandLineFlags; import org.chromium.base.test.util.DisabledTest; import org.chromium.base.test.util.Feature; import org.chromium.chrome.R; +import org.chromium.chrome.browser.ChromeSwitches; import org.chromium.chrome.browser.autofill.AutofillTestHelper; import org.chromium.chrome.browser.autofill.PersonalDataManager.AutofillProfile; import org.chromium.chrome.browser.autofill.PersonalDataManager.CreditCard; +import org.chromium.chrome.browser.payments.PaymentRequestTestRule.MainActivityStartCallback; import org.chromium.chrome.browser.tabmodel.TabModel; import org.chromium.chrome.browser.tabmodel.TabModel.TabLaunchType; import org.chromium.chrome.browser.tabmodel.TabModelUtils; +import org.chromium.chrome.test.ChromeActivityTestRule; +import org.chromium.chrome.test.ChromeJUnit4ClassRunner; import org.chromium.content_public.browser.LoadUrlParams; import java.util.concurrent.ExecutionException; @@ -25,10 +35,15 @@ * A payment integration test for dismissing the dialog when the user switches tabs or navigates * elsewhere. */ -public class PaymentRequestTabTest extends PaymentRequestTestBase { - public PaymentRequestTabTest() { - super("payment_request_dynamic_shipping_test.html"); - } +@RunWith(ChromeJUnit4ClassRunner.class) +@CommandLineFlags.Add({ + ChromeSwitches.DISABLE_FIRST_RUN_EXPERIENCE, + ChromeActivityTestRule.DISABLE_NETWORK_PREDICTION_FLAG, +}) +public class PaymentRequestTabTest implements MainActivityStartCallback { + @Rule + public PaymentRequestTestRule mPaymentRequestTestRule = + new PaymentRequestTestRule("payment_request_dynamic_shipping_test.html", this); @Override public void onMainActivityStarted() @@ -43,55 +58,58 @@ } /** If the user switches tabs somehow, the dialog is dismissed. */ + @Test @MediumTest @Feature({"Payments"}) - public void testDismissOnTabSwitch() throws InterruptedException, ExecutionException, - TimeoutException { - triggerUIAndWait(getReadyForInput()); - assertEquals(0, getDismissed().getCallCount()); + public void testDismissOnTabSwitch() + throws InterruptedException, ExecutionException, TimeoutException { + mPaymentRequestTestRule.triggerUIAndWait(mPaymentRequestTestRule.getReadyForInput()); + Assert.assertEquals(0, mPaymentRequestTestRule.getDismissed().getCallCount()); ThreadUtils.runOnUiThreadBlocking(new Runnable() { @Override public void run() { - getActivity().getTabCreator(false).createNewTab( + mPaymentRequestTestRule.getActivity().getTabCreator(false).createNewTab( new LoadUrlParams("about:blank"), TabLaunchType.FROM_CHROME_UI, null); } }); - getDismissed().waitForCallback(0); + mPaymentRequestTestRule.getDismissed().waitForCallback(0); } /** If the user closes the tab, the dialog is dismissed. */ //@MediumTest //@Feature({"Payments"}) // Disabled due to recent flakiness: crbug.com/661450. + @Test @DisabledTest - public void testDismissOnTabClose() throws InterruptedException, ExecutionException, - TimeoutException { - triggerUIAndWait(getReadyForInput()); - assertEquals(0, getDismissed().getCallCount()); + public void testDismissOnTabClose() + throws InterruptedException, ExecutionException, TimeoutException { + mPaymentRequestTestRule.triggerUIAndWait(mPaymentRequestTestRule.getReadyForInput()); + Assert.assertEquals(0, mPaymentRequestTestRule.getDismissed().getCallCount()); ThreadUtils.runOnUiThreadBlocking(new Runnable() { @Override public void run() { - TabModel currentModel = getActivity().getCurrentTabModel(); + TabModel currentModel = mPaymentRequestTestRule.getActivity().getCurrentTabModel(); TabModelUtils.closeCurrentTab(currentModel); } }); - getDismissed().waitForCallback(0); + mPaymentRequestTestRule.getDismissed().waitForCallback(0); } /** If the user navigates anywhere, the dialog is dismissed. */ + @Test @MediumTest @Feature({"Payments"}) - public void testDismissOnTabNavigate() throws InterruptedException, ExecutionException, - TimeoutException { - triggerUIAndWait(getReadyForInput()); - assertEquals(0, getDismissed().getCallCount()); + public void testDismissOnTabNavigate() + throws InterruptedException, ExecutionException, TimeoutException { + mPaymentRequestTestRule.triggerUIAndWait(mPaymentRequestTestRule.getReadyForInput()); + Assert.assertEquals(0, mPaymentRequestTestRule.getDismissed().getCallCount()); ThreadUtils.runOnUiThreadBlocking(new Runnable() { @Override public void run() { - TabModel currentModel = getActivity().getCurrentTabModel(); + TabModel currentModel = mPaymentRequestTestRule.getActivity().getCurrentTabModel(); TabModelUtils.getCurrentTab(currentModel).loadUrl(new LoadUrlParams("about:blank")); } }); - getDismissed().waitForCallback(0); + mPaymentRequestTestRule.getDismissed().waitForCallback(0); } }
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestUseStatsTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestUseStatsTest.java index a95219c8..f23aff8 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestUseStatsTest.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestUseStatsTest.java
@@ -7,11 +7,21 @@ import android.content.DialogInterface; import android.support.test.filters.MediumTest; +import org.junit.Assert; +import org.junit.Rule; +import org.junit.Test; +import org.junit.runner.RunWith; + +import org.chromium.base.test.util.CommandLineFlags; import org.chromium.base.test.util.Feature; import org.chromium.chrome.R; +import org.chromium.chrome.browser.ChromeSwitches; import org.chromium.chrome.browser.autofill.AutofillTestHelper; import org.chromium.chrome.browser.autofill.PersonalDataManager.AutofillProfile; import org.chromium.chrome.browser.autofill.PersonalDataManager.CreditCard; +import org.chromium.chrome.browser.payments.PaymentRequestTestRule.MainActivityStartCallback; +import org.chromium.chrome.test.ChromeActivityTestRule; +import org.chromium.chrome.test.ChromeJUnit4ClassRunner; import java.util.concurrent.ExecutionException; import java.util.concurrent.TimeoutException; @@ -20,11 +30,15 @@ * A payment integration test to validate that the use stats of Autofill profiles and credit cards * updated when they are used to complete a Payment Request transaction. */ -public class PaymentRequestUseStatsTest extends PaymentRequestTestBase { - public PaymentRequestUseStatsTest() { - // This merchant provides free shipping worldwide. - super("payment_request_free_shipping_test.html"); - } +@RunWith(ChromeJUnit4ClassRunner.class) +@CommandLineFlags.Add({ + ChromeSwitches.DISABLE_FIRST_RUN_EXPERIENCE, + ChromeActivityTestRule.DISABLE_NETWORK_PREDICTION_FLAG, +}) +public class PaymentRequestUseStatsTest implements MainActivityStartCallback { + @Rule + public PaymentRequestTestRule mPaymentRequestTestRule = + new PaymentRequestTestRule("payment_request_free_shipping_test.html", this); AutofillTestHelper mHelper; String mBillingAddressId; @@ -47,29 +61,36 @@ } /** Expect that using a profile and credit card to pay updates their usage stats. */ + @Test @MediumTest @Feature({"Payments"}) - public void testLogProfileAndCreditCardUse() throws InterruptedException, ExecutionException, - TimeoutException { - triggerUIAndWait(getReadyToPay()); + public void testLogProfileAndCreditCardUse() + throws InterruptedException, ExecutionException, TimeoutException { + mPaymentRequestTestRule.triggerUIAndWait(mPaymentRequestTestRule.getReadyToPay()); // Get the current date value just before the start of the Payment Request. long timeBeforeRecord = mHelper.getCurrentDateForTesting(); // Proceed with the payment. - clickAndWait(R.id.button_primary, getReadyForUnmaskInput()); - setTextInCardUnmaskDialogAndWait(R.id.card_unmask_input, "123", getReadyToUnmask()); - clickCardUnmaskButtonAndWait(DialogInterface.BUTTON_POSITIVE, getDismissed()); + mPaymentRequestTestRule.clickAndWait( + R.id.button_primary, mPaymentRequestTestRule.getReadyForUnmaskInput()); + mPaymentRequestTestRule.setTextInCardUnmaskDialogAndWait( + R.id.card_unmask_input, "123", mPaymentRequestTestRule.getReadyToUnmask()); + mPaymentRequestTestRule.clickCardUnmaskButtonAndWait( + DialogInterface.BUTTON_POSITIVE, mPaymentRequestTestRule.getDismissed()); // Get the current date value just after the end of the Payment Request. long timeAfterRecord = mHelper.getCurrentDateForTesting(); // Make sure the use counts were incremented and the use dates were set to the current time. - assertEquals(21, mHelper.getProfileUseCountForTesting(mBillingAddressId)); - assertTrue(timeBeforeRecord <= mHelper.getProfileUseDateForTesting(mBillingAddressId)); - assertTrue(timeAfterRecord >= mHelper.getProfileUseDateForTesting(mBillingAddressId)); - assertEquals(2, mHelper.getCreditCardUseCountForTesting(mCreditCardId)); - assertTrue(timeBeforeRecord <= mHelper.getCreditCardUseDateForTesting(mCreditCardId)); - assertTrue(timeAfterRecord >= mHelper.getCreditCardUseDateForTesting(mCreditCardId)); + Assert.assertEquals(21, mHelper.getProfileUseCountForTesting(mBillingAddressId)); + Assert.assertTrue( + timeBeforeRecord <= mHelper.getProfileUseDateForTesting(mBillingAddressId)); + Assert.assertTrue( + timeAfterRecord >= mHelper.getProfileUseDateForTesting(mBillingAddressId)); + Assert.assertEquals(2, mHelper.getCreditCardUseCountForTesting(mCreditCardId)); + Assert.assertTrue( + timeBeforeRecord <= mHelper.getCreditCardUseDateForTesting(mCreditCardId)); + Assert.assertTrue(timeAfterRecord >= mHelper.getCreditCardUseDateForTesting(mCreditCardId)); } }
diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/notifications/channels/ChannelDefinitionsTest.java b/chrome/android/junit/src/org/chromium/chrome/browser/notifications/channels/ChannelDefinitionsTest.java index ff933a0..2c386aa4 100644 --- a/chrome/android/junit/src/org/chromium/chrome/browser/notifications/channels/ChannelDefinitionsTest.java +++ b/chrome/android/junit/src/org/chromium/chrome/browser/notifications/channels/ChannelDefinitionsTest.java
@@ -20,8 +20,7 @@ public class ChannelDefinitionsTest { @Test public void testNoOverlapBetweenStartupAndLegacyChannelIds() throws Exception { - ChannelDefinitions channelDefinitions = new ChannelDefinitions(); - assertThat(channelDefinitions.getStartupChannelIds(), - everyItem(not(isIn(channelDefinitions.getLegacyChannelIds())))); + assertThat(ChannelDefinitions.getStartupChannelIds(), + everyItem(not(isIn(ChannelDefinitions.getLegacyChannelIds())))); } } \ No newline at end of file
diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/notifications/channels/ChannelsInitializerTest.java b/chrome/android/junit/src/org/chromium/chrome/browser/notifications/channels/ChannelsInitializerTest.java deleted file mode 100644 index 75fd5f4..0000000 --- a/chrome/android/junit/src/org/chromium/chrome/browser/notifications/channels/ChannelsInitializerTest.java +++ /dev/null
@@ -1,170 +0,0 @@ -// Copyright 2017 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.notifications.channels; - -import static org.hamcrest.Matchers.containsInAnyOrder; -import static org.hamcrest.Matchers.empty; -import static org.hamcrest.Matchers.hasSize; -import static org.hamcrest.Matchers.is; -import static org.hamcrest.Matchers.not; -import static org.junit.Assert.assertThat; - -import android.app.NotificationManager; - -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.junit.runners.BlockJUnit4ClassRunner; - -import org.chromium.chrome.test.util.browser.notifications.MockNotificationManagerProxy; - -/** - * Unit tests for ChannelsInitializer. - */ -@RunWith(BlockJUnit4ClassRunner.class) -public class ChannelsInitializerTest { - private ChannelsInitializer mChannelsInitializer; - private MockNotificationManagerProxy mMockNotificationManager; - - @Before - public void setUp() throws Exception { - mMockNotificationManager = new MockNotificationManagerProxy(); - mChannelsInitializer = - new ChannelsInitializer(mMockNotificationManager, new ChannelDefinitions()); - } - - @Test - public void testDeleteLegacyChannels_noopOnCurrentDefinitions() throws Exception { - assertThat(mMockNotificationManager.getNotificationChannelIds(), is(empty())); - - mChannelsInitializer.deleteLegacyChannels(); - assertThat(mMockNotificationManager.getNotificationChannelIds(), is(empty())); - - mChannelsInitializer.initializeStartupChannels(); - assertThat(mMockNotificationManager.getNotificationChannelIds(), is(not(empty()))); - - int nChannels = mMockNotificationManager.getNotificationChannelIds().size(); - mChannelsInitializer.deleteLegacyChannels(); - assertThat(mMockNotificationManager.getNotificationChannelIds(), hasSize(nChannels)); - } - - @Test - public void testInitializeStartupChannels() throws Exception { - mChannelsInitializer.initializeStartupChannels(); - assertThat(mMockNotificationManager.getNotificationChannelIds(), - containsInAnyOrder(ChannelDefinitions.CHANNEL_ID_BROWSER, - ChannelDefinitions.CHANNEL_ID_DOWNLOADS, - ChannelDefinitions.CHANNEL_ID_INCOGNITO, - ChannelDefinitions.CHANNEL_ID_SITES, ChannelDefinitions.CHANNEL_ID_MEDIA)); - } - - @Test - public void testEnsureInitialized_browserChannel() throws Exception { - mChannelsInitializer.ensureInitialized(ChannelDefinitions.CHANNEL_ID_BROWSER); - - assertThat(mMockNotificationManager.getChannels().size(), is(1)); - ChannelDefinitions.Channel channel = mMockNotificationManager.getChannels().get(0); - assertThat(channel.mId, is(ChannelDefinitions.CHANNEL_ID_BROWSER)); - assertThat( - channel.mNameResId, is(org.chromium.chrome.R.string.notification_category_browser)); - assertThat(channel.mImportance, is(NotificationManager.IMPORTANCE_LOW)); - assertThat(channel.mGroupId, is(ChannelDefinitions.CHANNEL_GROUP_ID_GENERAL)); - - assertThat(mMockNotificationManager.getNotificationChannelGroups().size(), is(1)); - ChannelDefinitions.ChannelGroup group = - mMockNotificationManager.getNotificationChannelGroups().get(0); - assertThat(group.mId, is(ChannelDefinitions.CHANNEL_GROUP_ID_GENERAL)); - assertThat(group.mNameResId, - is(org.chromium.chrome.R.string.notification_category_group_general)); - } - - @Test - public void testEnsureInitialized_downloadsChannel() throws Exception { - mChannelsInitializer.ensureInitialized(ChannelDefinitions.CHANNEL_ID_DOWNLOADS); - - assertThat(mMockNotificationManager.getChannels().size(), is(1)); - ChannelDefinitions.Channel channel = mMockNotificationManager.getChannels().get(0); - assertThat(channel.mId, is(ChannelDefinitions.CHANNEL_ID_DOWNLOADS)); - assertThat(channel.mNameResId, - is(org.chromium.chrome.R.string.notification_category_downloads)); - assertThat(channel.mImportance, is(NotificationManager.IMPORTANCE_LOW)); - assertThat(channel.mGroupId, is(ChannelDefinitions.CHANNEL_GROUP_ID_GENERAL)); - - assertThat(mMockNotificationManager.getNotificationChannelGroups().size(), is(1)); - ChannelDefinitions.ChannelGroup group = - mMockNotificationManager.getNotificationChannelGroups().get(0); - assertThat(group.mId, is(ChannelDefinitions.CHANNEL_GROUP_ID_GENERAL)); - assertThat(group.mNameResId, - is(org.chromium.chrome.R.string.notification_category_group_general)); - } - - @Test - public void testEnsureInitialized_incognitoChannel() throws Exception { - mChannelsInitializer.ensureInitialized(ChannelDefinitions.CHANNEL_ID_INCOGNITO); - - assertThat(mMockNotificationManager.getChannels().size(), is(1)); - ChannelDefinitions.Channel channel = mMockNotificationManager.getChannels().get(0); - assertThat(channel.mId, is(ChannelDefinitions.CHANNEL_ID_INCOGNITO)); - assertThat(channel.mNameResId, - is(org.chromium.chrome.R.string.notification_category_incognito)); - assertThat(channel.mImportance, is(NotificationManager.IMPORTANCE_LOW)); - assertThat(channel.mGroupId, is(ChannelDefinitions.CHANNEL_GROUP_ID_GENERAL)); - - assertThat(mMockNotificationManager.getNotificationChannelGroups().size(), is(1)); - ChannelDefinitions.ChannelGroup group = - mMockNotificationManager.getNotificationChannelGroups().get(0); - assertThat(group.mId, is(ChannelDefinitions.CHANNEL_GROUP_ID_GENERAL)); - assertThat(group.mNameResId, - is(org.chromium.chrome.R.string.notification_category_group_general)); - } - - @Test - public void testEnsureInitialized_mediaChannel() throws Exception { - mChannelsInitializer.ensureInitialized(ChannelDefinitions.CHANNEL_ID_MEDIA); - - assertThat(mMockNotificationManager.getChannels().size(), is(1)); - ChannelDefinitions.Channel channel = mMockNotificationManager.getChannels().get(0); - assertThat(channel.mId, is(ChannelDefinitions.CHANNEL_ID_MEDIA)); - assertThat( - channel.mNameResId, is(org.chromium.chrome.R.string.notification_category_media)); - assertThat(channel.mImportance, is(NotificationManager.IMPORTANCE_LOW)); - assertThat(channel.mGroupId, is(ChannelDefinitions.CHANNEL_GROUP_ID_GENERAL)); - - assertThat(mMockNotificationManager.getNotificationChannelGroups().size(), is(1)); - ChannelDefinitions.ChannelGroup group = - mMockNotificationManager.getNotificationChannelGroups().get(0); - assertThat(group.mId, is(ChannelDefinitions.CHANNEL_GROUP_ID_GENERAL)); - assertThat(group.mNameResId, - is(org.chromium.chrome.R.string.notification_category_group_general)); - } - - @Test - public void testEnsureInitialized_sitesChannel() throws Exception { - mChannelsInitializer.ensureInitialized(ChannelDefinitions.CHANNEL_ID_SITES); - - assertThat(mMockNotificationManager.getChannels().size(), is(1)); - - ChannelDefinitions.Channel channel = mMockNotificationManager.getChannels().get(0); - assertThat(channel.mId, is(ChannelDefinitions.CHANNEL_ID_SITES)); - assertThat( - channel.mNameResId, is(org.chromium.chrome.R.string.notification_category_sites)); - assertThat(channel.mImportance, is(NotificationManager.IMPORTANCE_DEFAULT)); - assertThat(channel.mGroupId, is(ChannelDefinitions.CHANNEL_GROUP_ID_GENERAL)); - - assertThat(mMockNotificationManager.getNotificationChannelGroups().size(), is(1)); - ChannelDefinitions.ChannelGroup group = - mMockNotificationManager.getNotificationChannelGroups().get(0); - assertThat(group.mId, is(ChannelDefinitions.CHANNEL_GROUP_ID_GENERAL)); - assertThat(group.mNameResId, - is(org.chromium.chrome.R.string.notification_category_group_general)); - } - - @Test - public void testEnsureInitialized_multipleCalls() throws Exception { - mChannelsInitializer.ensureInitialized(ChannelDefinitions.CHANNEL_ID_SITES); - mChannelsInitializer.ensureInitialized(ChannelDefinitions.CHANNEL_ID_BROWSER); - assertThat(mMockNotificationManager.getChannels().size(), is(2)); - } -} \ No newline at end of file
diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/notifications/channels/ChannelsUpdaterTest.java b/chrome/android/junit/src/org/chromium/chrome/browser/notifications/channels/ChannelsUpdaterTest.java index 43f7050..f381e470 100644 --- a/chrome/android/junit/src/org/chromium/chrome/browser/notifications/channels/ChannelsUpdaterTest.java +++ b/chrome/android/junit/src/org/chromium/chrome/browser/notifications/channels/ChannelsUpdaterTest.java
@@ -7,9 +7,14 @@ import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.Matchers.containsInAnyOrder; import static org.hamcrest.Matchers.greaterThan; +import static org.hamcrest.Matchers.hasSize; import static org.hamcrest.Matchers.is; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; import android.app.NotificationManager; +import android.content.res.Resources; import org.junit.Before; import org.junit.Test; @@ -17,22 +22,32 @@ import org.junit.runners.BlockJUnit4ClassRunner; import org.chromium.base.test.util.InMemorySharedPreferences; +import org.chromium.chrome.browser.notifications.NotificationManagerProxy; import org.chromium.chrome.test.util.browser.notifications.MockNotificationManagerProxy; +import java.util.ArrayList; +import java.util.List; + /** * Tests that ChannelsUpdater correctly initializes channels on the notification manager. */ @RunWith(BlockJUnit4ClassRunner.class) public class ChannelsUpdaterTest { - private MockNotificationManagerProxy mMockNotificationManager; + private NotificationManagerProxy mMockNotificationManager; private InMemorySharedPreferences mMockSharedPreferences; private ChannelsInitializer mChannelsInitializer; + private Resources mMockResources; @Before public void setUp() throws Exception { mMockNotificationManager = new MockNotificationManagerProxy(); - mChannelsInitializer = - new ChannelsInitializer(mMockNotificationManager, new ChannelDefinitions()); + + // Mock the resources to prevent nullpointers on string resource lookups (none of these + // tests need the real strings, if they did this would need to be an instrumentation test). + mMockResources = mock(Resources.class); + when(mMockResources.getString(any(Integer.class))).thenReturn(""); + + mChannelsInitializer = new ChannelsInitializer(mMockNotificationManager, mMockResources); mMockSharedPreferences = new InMemorySharedPreferences(); } @@ -73,7 +88,7 @@ false /* isAtLeastO */, mMockSharedPreferences, mChannelsInitializer, 21); updater.updateChannels(); - assertThat(mMockNotificationManager.getChannels().size(), is(0)); + assertThat(mMockNotificationManager.getNotificationChannels(), hasSize(0)); assertThat(mMockSharedPreferences.getInt(ChannelsUpdater.CHANNELS_VERSION_KEY, -1), is(-1)); } @@ -83,8 +98,8 @@ true /* isAtLeastO */, mMockSharedPreferences, mChannelsInitializer, 21); updater.updateChannels(); - assertThat(mMockNotificationManager.getChannels().size(), is(greaterThan(0))); - assertThat(mMockNotificationManager.getNotificationChannelIds(), + assertThat(mMockNotificationManager.getNotificationChannels(), hasSize((greaterThan(0)))); + assertThat(getChannelIds(mMockNotificationManager.getNotificationChannels()), containsInAnyOrder(ChannelDefinitions.CHANNEL_ID_BROWSER, ChannelDefinitions.CHANNEL_ID_DOWNLOADS, ChannelDefinitions.CHANNEL_ID_INCOGNITO, @@ -92,34 +107,31 @@ assertThat(mMockSharedPreferences.getInt(ChannelsUpdater.CHANNELS_VERSION_KEY, -1), is(21)); } - // Warnings suppressed in order to construct the legacy channels with invalid channel ids. - @SuppressWarnings("WrongConstant") @Test public void testUpdateChannels_deletesLegacyChannelsAndCreatesExpectedOnes() throws Exception { - // Fake some legacy channels (since we don't have any yet). - ChannelDefinitions channelDefinitions = new ChannelDefinitions() { - @Override - public String[] getLegacyChannelIds() { - return new String[] {"OldChannel", "AnotherOldChannel"}; - } - }; - mMockNotificationManager.createNotificationChannel(new ChannelDefinitions.Channel( - "OldChannel", 8292304, NotificationManager.IMPORTANCE_HIGH, - ChannelDefinitions.CHANNEL_GROUP_ID_GENERAL)); - mMockNotificationManager.createNotificationChannel( - new ChannelDefinitions.Channel("AnotherOldChannel", 8292304, - NotificationManager.IMPORTANCE_LOW, "OldChannelGroup")); - assertThat(mMockNotificationManager.getNotificationChannelIds(), - containsInAnyOrder("OldChannel", "AnotherOldChannel")); + // Set up any legacy channels. + for (String id : ChannelDefinitions.getLegacyChannelIds()) { + mMockNotificationManager.createNotificationChannel( + new Channel(id, id, NotificationManager.IMPORTANCE_LOW, + ChannelDefinitions.CHANNEL_GROUP_ID_GENERAL)); + } ChannelsUpdater updater = new ChannelsUpdater(true /* isAtLeastO */, mMockSharedPreferences, - new ChannelsInitializer(mMockNotificationManager, channelDefinitions), 12); + new ChannelsInitializer(mMockNotificationManager, mMockResources), 12); updater.updateChannels(); - assertThat(mMockNotificationManager.getNotificationChannelIds(), + assertThat(getChannelIds(mMockNotificationManager.getNotificationChannels()), containsInAnyOrder(ChannelDefinitions.CHANNEL_ID_BROWSER, ChannelDefinitions.CHANNEL_ID_DOWNLOADS, ChannelDefinitions.CHANNEL_ID_INCOGNITO, ChannelDefinitions.CHANNEL_ID_SITES, ChannelDefinitions.CHANNEL_ID_MEDIA)); } + + private static List<String> getChannelIds(List<Channel> channels) { + List<String> ids = new ArrayList<>(); + for (Channel ch : channels) { + ids.add(ch.getId()); + } + return ids; + } } \ No newline at end of file
diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/offlinepages/OfflinePageBridgeUnitTest.java b/chrome/android/junit/src/org/chromium/chrome/browser/offlinepages/OfflinePageBridgeUnitTest.java index a4cfab3..3fede53 100644 --- a/chrome/android/junit/src/org/chromium/chrome/browser/offlinepages/OfflinePageBridgeUnitTest.java +++ b/chrome/android/junit/src/org/chromium/chrome/browser/offlinepages/OfflinePageBridgeUnitTest.java
@@ -16,7 +16,6 @@ import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; - import org.mockito.ArgumentCaptor; import org.mockito.Captor; import org.mockito.MockitoAnnotations; @@ -71,6 +70,9 @@ ArgumentCaptor<String[]> mIdsArgument; @Captor + ArgumentCaptor<long[]> mOfflineIdsArgument; + + @Captor ArgumentCaptor<Callback<Integer>> mDeleteCallbackArgument; /** @@ -225,6 +227,51 @@ verify(callback, times(1)).onResult(any(Integer.class)); } + @Test + @Feature({"OfflinePages"}) + public void testDeletePagesByOfflineIds_listOfOfflineIdsNull() { + // -1 means to check for null in the Answer. + final int itemCount = -1; + + answerDeletePagesByOfflineIds(itemCount); + Callback<Integer> callback = createDeletePageCallback(); + List<Long> list = null; + + mBridge.deletePagesByOfflineId(list, callback); + + verify(callback, times(1)).onResult(any(Integer.class)); + } + + @Test + @Feature({"OfflinePages"}) + public void testDeletePagesByOfflineIds_listOfOfflineIdsEmpty() { + final int itemCount = 0; + + answerDeletePagesByOfflineIds(itemCount); + Callback<Integer> callback = createDeletePageCallback(); + List<Long> list = new ArrayList<>(); + + mBridge.deletePagesByOfflineId(list, callback); + + verify(callback, times(1)).onResult(any(Integer.class)); + } + + @Test + @Feature({"OfflinePages"}) + public void testDeletePagesByOfflineIds() { + final int itemCount = 2; + + answerDeletePagesByOfflineIds(itemCount); + Callback<Integer> callback = createDeletePageCallback(); + List<Long> list = new ArrayList<>(); + list.add(Long.valueOf(1)); + list.add(Long.valueOf(2)); + + mBridge.deletePagesByOfflineId(list, callback); + + verify(callback, times(1)).onResult(any(Integer.class)); + } + /** Performs a proper cast from Object to a List<OfflinePageItem>. */ private static List<OfflinePageItem> convertToListOfOfflinePages(Object o) { @SuppressWarnings("unchecked") @@ -293,6 +340,27 @@ mCallbackArgument.capture()); } + private void answerDeletePagesByOfflineIds(final int itemCount) { + Answer<Void> answer = new Answer<Void>() { + @Override + public Void answer(InvocationOnMock invocation) { + long[] offlineIds = mOfflineIdsArgument.getValue(); + + if (itemCount < 0) { + assertEquals(offlineIds, null); + } else { + assertEquals(offlineIds.length, itemCount); + } + mDeleteCallbackArgument.getValue().onResult(Integer.valueOf(0)); + + return null; + } + }; + + doAnswer(answer).when(mBridge).nativeDeletePagesByOfflineId( + anyLong(), mOfflineIdsArgument.capture(), mDeleteCallbackArgument.capture()); + } + private void answerDeletePagesByClientIds(final int itemCount) { Answer<Void> answer = new Answer<Void>() { @Override
diff --git a/chrome/browser/BUILD.gn b/chrome/browser/BUILD.gn index 7b3187b8..cf3bf21c 100644 --- a/chrome/browser/BUILD.gn +++ b/chrome/browser/BUILD.gn
@@ -1804,8 +1804,8 @@ "renderer_context_menu/context_menu_content_type_platform_app.h", "renderer_host/chrome_extension_message_filter.cc", "renderer_host/chrome_extension_message_filter.h", - "safe_browsing/chrome_cleaner/chrome_cleaner_dialog_controller.cc", - "safe_browsing/chrome_cleaner/chrome_cleaner_dialog_controller.h", + "safe_browsing/chrome_cleaner/chrome_cleaner_dialog_controller_win.cc", + "safe_browsing/chrome_cleaner/chrome_cleaner_dialog_controller_win.h", "safe_browsing/settings_reset_prompt/default_settings_fetcher.cc", "safe_browsing/settings_reset_prompt/default_settings_fetcher.h", "safe_browsing/settings_reset_prompt/extension_info.cc",
diff --git a/chrome/browser/android/chrome_feature_list.cc b/chrome/browser/android/chrome_feature_list.cc index 62038f2c..3b545b33 100644 --- a/chrome/browser/android/chrome_feature_list.cc +++ b/chrome/browser/android/chrome_feature_list.cc
@@ -59,6 +59,7 @@ &kContextualSuggestionsCarousel, &kCustomContextMenu, &kCustomFeedbackUi, + &kDownloadHomeShowStorageInfo, &data_reduction_proxy::features::kDataReductionMainMenu, &data_reduction_proxy::features::kDataReductionSiteBreakdown, &kFullscreenActivity, @@ -155,6 +156,9 @@ const base::Feature kDownloadAutoResumptionThrottling{ "DownloadAutoResumptionThrottling", base::FEATURE_ENABLED_BY_DEFAULT}; +const base::Feature kDownloadHomeShowStorageInfo{ + "DownloadHomeShowStorageInfo", base::FEATURE_DISABLED_BY_DEFAULT}; + const base::Feature kFullscreenActivity{"FullscreenActivity", base::FEATURE_DISABLED_BY_DEFAULT};
diff --git a/chrome/browser/android/chrome_feature_list.h b/chrome/browser/android/chrome_feature_list.h index 81c6071..6fa070e 100644 --- a/chrome/browser/android/chrome_feature_list.h +++ b/chrome/browser/android/chrome_feature_list.h
@@ -29,6 +29,7 @@ extern const base::Feature kCustomContextMenu; extern const base::Feature kCustomFeedbackUi; extern const base::Feature kDownloadAutoResumptionThrottling; +extern const base::Feature kDownloadHomeShowStorageInfo; extern const base::Feature kFullscreenActivity; extern const base::Feature kImportantSitesInCBD; extern const base::Feature kImprovedA2HS;
diff --git a/chrome/browser/android/offline_pages/offline_page_bridge.cc b/chrome/browser/android/offline_pages/offline_page_bridge.cc index b93155a..7a54ab1 100644 --- a/chrome/browser/android/offline_pages/offline_page_bridge.cc +++ b/chrome/browser/android/offline_pages/offline_page_bridge.cc
@@ -385,6 +385,20 @@ client_ids, base::Bind(&DeletePageCallback, j_callback_ref)); } +void OfflinePageBridge::DeletePagesByOfflineId( + JNIEnv* env, + const JavaParamRef<jobject>& obj, + const JavaParamRef<jlongArray>& j_offline_ids_array, + const JavaParamRef<jobject>& j_callback_obj) { + ScopedJavaGlobalRef<jobject> j_callback_ref; + j_callback_ref.Reset(env, j_callback_obj); + std::vector<int64_t> offline_ids; + base::android::JavaLongArrayToInt64Vector(env, j_offline_ids_array, + &offline_ids); + offline_page_model_->DeletePagesByOfflineId( + offline_ids, base::Bind(&DeletePageCallback, j_callback_ref)); +} + void OfflinePageBridge::GetPagesByClientId( JNIEnv* env, const JavaParamRef<jobject>& obj, @@ -403,6 +417,27 @@ client_ids, base::Bind(&MultipleOfflinePageItemCallback, j_result_ref, j_callback_ref)); } +void OfflinePageBridge::GetPagesForNamespace( + JNIEnv* env, + const JavaParamRef<jobject>& obj, + const JavaParamRef<jobject>& j_result_obj, + const JavaParamRef<jstring>& j_namespace, + const JavaParamRef<jobject>& j_callback_obj) { + ScopedJavaGlobalRef<jobject> j_result_ref(env, j_result_obj); + + ScopedJavaGlobalRef<jobject> j_callback_ref; + j_callback_ref.Reset(env, j_callback_obj); + + std::string name_space = ConvertJavaStringToUTF8(env, j_namespace); + + OfflinePageModelQueryBuilder builder; + builder.RequireNamespace(name_space); + + offline_page_model_->GetPagesMatchingQuery( + builder.Build(offline_page_model_->GetPolicyController()), + base::Bind(&MultipleOfflinePageItemCallback, j_result_ref, + j_callback_ref)); +} void OfflinePageBridge::SelectPageForOnlineUrl( JNIEnv* env,
diff --git a/chrome/browser/android/offline_pages/offline_page_bridge.h b/chrome/browser/android/offline_pages/offline_page_bridge.h index db898dfb..49b8d5a 100644 --- a/chrome/browser/android/offline_pages/offline_page_bridge.h +++ b/chrome/browser/android/offline_pages/offline_page_bridge.h
@@ -69,6 +69,12 @@ const base::android::JavaParamRef<jobjectArray>& j_ids_array, const base::android::JavaParamRef<jobject>& j_callback_obj); + void DeletePagesByOfflineId( + JNIEnv* env, + const base::android::JavaParamRef<jobject>& obj, + const base::android::JavaParamRef<jlongArray>& j_offline_ids_array, + const base::android::JavaParamRef<jobject>& j_callback_obj); + void GetPagesByClientId( JNIEnv* env, const base::android::JavaParamRef<jobject>& obj, @@ -77,6 +83,13 @@ const base::android::JavaParamRef<jobjectArray>& j_ids_array, const base::android::JavaParamRef<jobject>& j_callback_obj); + void GetPagesForNamespace( + JNIEnv* env, + const base::android::JavaParamRef<jobject>& obj, + const base::android::JavaParamRef<jobject>& j_result_obj, + const base::android::JavaParamRef<jstring>& j_namespace, + const base::android::JavaParamRef<jobject>& j_callback_obj); + void SelectPageForOnlineUrl( JNIEnv* env, const base::android::JavaParamRef<jobject>& obj,
diff --git a/chrome/browser/android/preferences/pref_service_bridge.cc b/chrome/browser/android/preferences/pref_service_bridge.cc index b60b402..ab47a4f 100644 --- a/chrome/browser/android/preferences/pref_service_bridge.cc +++ b/chrome/browser/android/preferences/pref_service_bridge.cc
@@ -43,7 +43,7 @@ #include "components/metrics/metrics_pref_names.h" #include "components/password_manager/core/common/password_manager_pref_names.h" #include "components/prefs/pref_service.h" -#include "components/safe_browsing_db/safe_browsing_prefs.h" +#include "components/safe_browsing/common/safe_browsing_prefs.h" #include "components/signin/core/common/signin_pref_names.h" #include "components/strings/grit/components_locale_settings.h" #include "components/translate/core/browser/translate_pref_names.h"
diff --git a/chrome/browser/android/vr_shell/BUILD.gn b/chrome/browser/android/vr_shell/BUILD.gn index 404275f..45afdcf 100644 --- a/chrome/browser/android/vr_shell/BUILD.gn +++ b/chrome/browser/android/vr_shell/BUILD.gn
@@ -42,10 +42,14 @@ "textures/insecure_content_transient_texture.h", "textures/loading_indicator_texture.cc", "textures/loading_indicator_texture.h", + "textures/system_indicator_texture.cc", + "textures/system_indicator_texture.h", "textures/ui_texture.cc", "textures/ui_texture.h", "textures/url_bar_texture.cc", "textures/url_bar_texture.h", + "ui_elements/audio_capture_indicator.cc", + "ui_elements/audio_capture_indicator.h", "ui_elements/close_button.cc", "ui_elements/close_button.h", "ui_elements/loading_indicator.cc", @@ -60,6 +64,8 @@ "ui_elements/ui_element.h", "ui_elements/url_bar.cc", "ui_elements/url_bar.h", + "ui_elements/video_capture_indicator.cc", + "ui_elements/video_capture_indicator.h", "ui_interface.h", "ui_scene.cc", "ui_scene.h",
diff --git a/chrome/browser/android/vr_shell/textures/insecure_content_permanent_texture.h b/chrome/browser/android/vr_shell/textures/insecure_content_permanent_texture.h index 1fbc1b52..ae48322 100644 --- a/chrome/browser/android/vr_shell/textures/insecure_content_permanent_texture.h +++ b/chrome/browser/android/vr_shell/textures/insecure_content_permanent_texture.h
@@ -5,6 +5,7 @@ #ifndef CHROME_BROWSER_ANDROID_VR_SHELL_TEXTURES_INSECURE_CONTENT_PERMANENT_TEXTURE_H_ #define CHROME_BROWSER_ANDROID_VR_SHELL_TEXTURES_INSECURE_CONTENT_PERMANENT_TEXTURE_H_ +#include "base/macros.h" #include "chrome/browser/android/vr_shell/textures/ui_texture.h" namespace vr_shell { @@ -20,6 +21,8 @@ void Draw(SkCanvas* canvas, const gfx::Size& texture_size) override; gfx::SizeF size_; + + DISALLOW_COPY_AND_ASSIGN(InsecureContentPermanentTexture); }; } // namespace vr_shell
diff --git a/chrome/browser/android/vr_shell/textures/insecure_content_transient_texture.h b/chrome/browser/android/vr_shell/textures/insecure_content_transient_texture.h index 8a11938b..8cabcab 100644 --- a/chrome/browser/android/vr_shell/textures/insecure_content_transient_texture.h +++ b/chrome/browser/android/vr_shell/textures/insecure_content_transient_texture.h
@@ -5,6 +5,7 @@ #ifndef CHROME_BROWSER_ANDROID_VR_SHELL_TEXTURES_INSECURE_CONTENT_TRANSIENT_TEXTURE_H_ #define CHROME_BROWSER_ANDROID_VR_SHELL_TEXTURES_INSECURE_CONTENT_TRANSIENT_TEXTURE_H_ +#include "base/macros.h" #include "chrome/browser/android/vr_shell/textures/ui_texture.h" namespace vr_shell { @@ -20,6 +21,8 @@ void Draw(SkCanvas* sk_canvas, const gfx::Size& texture_size) override; gfx::SizeF size_; + + DISALLOW_COPY_AND_ASSIGN(InsecureContentTransientTexture); }; } // namespace vr_shell
diff --git a/chrome/browser/android/vr_shell/textures/system_indicator_texture.cc b/chrome/browser/android/vr_shell/textures/system_indicator_texture.cc new file mode 100644 index 0000000..69d24dd --- /dev/null +++ b/chrome/browser/android/vr_shell/textures/system_indicator_texture.cc
@@ -0,0 +1,101 @@ +// Copyright 2017 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. + +#include "chrome/browser/android/vr_shell/textures/system_indicator_texture.h" + +#include "base/strings/utf_string_conversions.h" +#include "cc/paint/skia_paint_canvas.h" +#include "ui/base/l10n/l10n_util.h" +#include "ui/gfx/canvas.h" +#include "ui/gfx/font_list.h" +#include "ui/gfx/geometry/rect.h" +#include "ui/gfx/geometry/vector2d.h" +#include "ui/gfx/paint_vector_icon.h" +#include "ui/gfx/render_text.h" +#include "ui/gfx/vector_icon_types.h" + +namespace vr_shell { + +namespace { + +const SkColor kBackgroundColor = SK_ColorWHITE; +const SkColor kForegroundColor = 0xFF444444; +constexpr float kBorderFactor = 0.1; +constexpr float kIconSizeFactor = 0.7; +constexpr float kFontSizeFactor = 0.40; +constexpr float kTextHeightFactor = 1.0 - 2 * kBorderFactor; +constexpr float kTextWidthFactor = 4.0 - 3 * kBorderFactor - kIconSizeFactor; + +} // namespace + +SystemIndicatorTexture::SystemIndicatorTexture(const gfx::VectorIcon& icon, + int message_id) + : icon_(icon), message_id_(message_id) {} + +SystemIndicatorTexture::~SystemIndicatorTexture() = default; + +void SystemIndicatorTexture::Draw(SkCanvas* sk_canvas, + const gfx::Size& texture_size) { + cc::SkiaPaintCanvas paint_canvas(sk_canvas); + gfx::Canvas gfx_canvas(&paint_canvas, 1.0f); + gfx::Canvas* canvas = &gfx_canvas; + + DCHECK(texture_size.height() * 4 == texture_size.width()); + size_.set_height(texture_size.height()); + SkPaint paint; + paint.setColor(kBackgroundColor); + + base::string16 text; + + // TODO(acondor): Set proper strings in resources files. + if (message_id_) + text = l10n_util::GetStringUTF16(message_id_); + else + text = base::UTF8ToUTF16("<message>"); + + auto fonts = GetFontList(size_.height() * kFontSizeFactor, text); + gfx::Rect text_size(0, kTextHeightFactor * size_.height()); + + std::vector<std::unique_ptr<gfx::RenderText>> lines = + PrepareDrawStringRect(text, fonts, kForegroundColor, &text_size, 0); + + DCHECK_LE(text_size.width(), kTextWidthFactor * size_.height()); + // Setting background size giving some extra lateral padding to the text. + size_.set_width((5 * kBorderFactor + kIconSizeFactor) * size_.height() + + text_size.width()); + float radius = size_.height() * kBorderFactor; + sk_canvas->drawRoundRect(SkRect::MakeWH(size_.width(), size_.height()), + radius, radius, paint); + + canvas->Save(); + canvas->Translate(gfx::Vector2d( + IsRTL() ? 4 * kBorderFactor * size_.height() + text_size.width() + : size_.height() * kBorderFactor, + size_.height() * (1.0 - kIconSizeFactor) / 2.0)); + PaintVectorIcon(canvas, icon_, size_.height() * kIconSizeFactor, + kForegroundColor); + canvas->Restore(); + + canvas->Save(); + canvas->Translate(gfx::Vector2d( + size_.height() * + (IsRTL() ? 2 * kBorderFactor : 3 * kBorderFactor + kIconSizeFactor), + size_.height() * kBorderFactor)); + for (auto& render_text : lines) + render_text->Draw(canvas); + canvas->Restore(); +} + +gfx::Size SystemIndicatorTexture::GetPreferredTextureSize( + int maximum_width) const { + // Ensuring height is a quarter of the width. + int height = maximum_width / 4; + return gfx::Size(height * 4, height); +} + +gfx::SizeF SystemIndicatorTexture::GetDrawnSize() const { + return size_; +} + +} // namespace vr_shell
diff --git a/chrome/browser/android/vr_shell/textures/system_indicator_texture.h b/chrome/browser/android/vr_shell/textures/system_indicator_texture.h new file mode 100644 index 0000000..b20ef997 --- /dev/null +++ b/chrome/browser/android/vr_shell/textures/system_indicator_texture.h
@@ -0,0 +1,33 @@ +// Copyright 2017 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. + +#ifndef CHROME_BROWSER_ANDROID_VR_SHELL_TEXTURES_SYSTEM_INDICATOR_TEXTURE_H_ +#define CHROME_BROWSER_ANDROID_VR_SHELL_TEXTURES_SYSTEM_INDICATOR_TEXTURE_H_ + +#include "base/macros.h" +#include "chrome/browser/android/vr_shell/textures/ui_texture.h" +#include "ui/gfx/vector_icon_types.h" + +namespace vr_shell { + +class SystemIndicatorTexture : public UiTexture { + public: + SystemIndicatorTexture(const gfx::VectorIcon& icon, int message_id); + ~SystemIndicatorTexture() override; + gfx::Size GetPreferredTextureSize(int width) const override; + gfx::SizeF GetDrawnSize() const override; + + private: + void Draw(SkCanvas* canvas, const gfx::Size& texture_size) override; + + gfx::SizeF size_; + const gfx::VectorIcon& icon_; + int message_id_; + + DISALLOW_COPY_AND_ASSIGN(SystemIndicatorTexture); +}; + +} // namespace vr_shell + +#endif // CHROME_BROWSER_ANDROID_VR_SHELL_TEXTURES_SYSTEM_INDICATOR_TEXTURE_H_
diff --git a/chrome/browser/android/vr_shell/textures/ui_texture.h b/chrome/browser/android/vr_shell/textures/ui_texture.h index 5154cd72..e0d3b3ec 100644 --- a/chrome/browser/android/vr_shell/textures/ui_texture.h +++ b/chrome/browser/android/vr_shell/textures/ui_texture.h
@@ -8,6 +8,7 @@ #include <memory> #include <vector> +#include "base/macros.h" #include "base/strings/string16.h" #include "third_party/skia/include/core/SkColor.h" #include "ui/gfx/geometry/rect.h" @@ -71,6 +72,8 @@ private: int draw_flags_ = 0; bool dirty_ = false; + + DISALLOW_COPY_AND_ASSIGN(UiTexture); }; } // namespace vr_shell
diff --git a/chrome/browser/android/vr_shell/textures/url_bar_texture.h b/chrome/browser/android/vr_shell/textures/url_bar_texture.h index c85e806..cf0a6ab2 100644 --- a/chrome/browser/android/vr_shell/textures/url_bar_texture.h +++ b/chrome/browser/android/vr_shell/textures/url_bar_texture.h
@@ -8,6 +8,7 @@ #include <memory> #include <vector> +#include "base/macros.h" #include "chrome/browser/android/vr_shell/textures/ui_texture.h" #include "url/gurl.h" @@ -41,6 +42,8 @@ GURL gurl_; GURL last_drawn_gurl_; std::vector<std::unique_ptr<gfx::RenderText>> gurl_render_texts_; + + DISALLOW_COPY_AND_ASSIGN(UrlBarTexture); }; } // namespace vr_shell
diff --git a/chrome/browser/android/vr_shell/ui_elements/audio_capture_indicator.cc b/chrome/browser/android/vr_shell/ui_elements/audio_capture_indicator.cc new file mode 100644 index 0000000..843383e4 --- /dev/null +++ b/chrome/browser/android/vr_shell/ui_elements/audio_capture_indicator.cc
@@ -0,0 +1,26 @@ +// Copyright 2017 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. + +#include "chrome/browser/android/vr_shell/ui_elements/audio_capture_indicator.h" + +#include "base/memory/ptr_util.h" +#include "chrome/browser/android/vr_shell/textures/system_indicator_texture.h" +#include "components/strings/grit/components_strings.h" +#include "ui/vector_icons/vector_icons.h" + +namespace vr_shell { + +// TODO(acondor): Set a proper string. +AudioCaptureIndicator::AudioCaptureIndicator(int preferred_width) + : TexturedElement(preferred_width), + texture_( + base::MakeUnique<SystemIndicatorTexture>(ui::kMicrophoneIcon, 0)) {} + +AudioCaptureIndicator::~AudioCaptureIndicator() = default; + +UiTexture* AudioCaptureIndicator::GetTexture() const { + return texture_.get(); +} + +} // namespace vr_shell
diff --git a/chrome/browser/android/vr_shell/ui_elements/audio_capture_indicator.h b/chrome/browser/android/vr_shell/ui_elements/audio_capture_indicator.h new file mode 100644 index 0000000..c400e58 --- /dev/null +++ b/chrome/browser/android/vr_shell/ui_elements/audio_capture_indicator.h
@@ -0,0 +1,31 @@ +// Copyright 2017 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. + +#ifndef CHROME_BROWSER_ANDROID_VR_SHELL_UI_ELEMENTS_AUDIO_CAPTURE_INDICATOR_H_ +#define CHROME_BROWSER_ANDROID_VR_SHELL_UI_ELEMENTS_AUDIO_CAPTURE_INDICATOR_H_ + +#include <memory> + +#include "base/macros.h" +#include "chrome/browser/android/vr_shell/ui_elements/textured_element.h" + +namespace vr_shell { + +class UiTexture; + +class AudioCaptureIndicator : public TexturedElement { + public: + explicit AudioCaptureIndicator(int preferred_width); + ~AudioCaptureIndicator() override; + + private: + UiTexture* GetTexture() const override; + std::unique_ptr<UiTexture> texture_; + + DISALLOW_COPY_AND_ASSIGN(AudioCaptureIndicator); +}; + +} // namespace vr_shell + +#endif // CHROME_BROWSER_ANDROID_VR_SHELL_UI_ELEMENTS_AUDIO_CAPTURE_INDICATOR_H_
diff --git a/chrome/browser/android/vr_shell/ui_elements/video_capture_indicator.cc b/chrome/browser/android/vr_shell/ui_elements/video_capture_indicator.cc new file mode 100644 index 0000000..5ad04a8c --- /dev/null +++ b/chrome/browser/android/vr_shell/ui_elements/video_capture_indicator.cc
@@ -0,0 +1,26 @@ +// Copyright 2017 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. + +#include "chrome/browser/android/vr_shell/ui_elements/video_capture_indicator.h" + +#include "base/memory/ptr_util.h" +#include "chrome/browser/android/vr_shell/textures/system_indicator_texture.h" +#include "components/strings/grit/components_strings.h" +#include "ui/vector_icons/vector_icons.h" + +namespace vr_shell { + +// TODO(acondor): Set a proper string. +VideoCaptureIndicator::VideoCaptureIndicator(int preferred_width) + : TexturedElement(preferred_width), + texture_(base::MakeUnique<SystemIndicatorTexture>(ui::kVideocamIcon, 0)) { +} + +VideoCaptureIndicator::~VideoCaptureIndicator() = default; + +UiTexture* VideoCaptureIndicator::GetTexture() const { + return texture_.get(); +} + +} // namespace vr_shell
diff --git a/chrome/browser/android/vr_shell/ui_elements/video_capture_indicator.h b/chrome/browser/android/vr_shell/ui_elements/video_capture_indicator.h new file mode 100644 index 0000000..8b39a407 --- /dev/null +++ b/chrome/browser/android/vr_shell/ui_elements/video_capture_indicator.h
@@ -0,0 +1,31 @@ +// Copyright 2017 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. + +#ifndef CHROME_BROWSER_ANDROID_VR_SHELL_UI_ELEMENTS_VIDEO_CAPTURE_INDICATOR_H_ +#define CHROME_BROWSER_ANDROID_VR_SHELL_UI_ELEMENTS_VIDEO_CAPTURE_INDICATOR_H_ + +#include <memory> + +#include "base/macros.h" +#include "chrome/browser/android/vr_shell/ui_elements/textured_element.h" + +namespace vr_shell { + +class UiTexture; + +class VideoCaptureIndicator : public TexturedElement { + public: + explicit VideoCaptureIndicator(int preferred_width); + ~VideoCaptureIndicator() override; + + private: + UiTexture* GetTexture() const override; + std::unique_ptr<UiTexture> texture_; + + DISALLOW_COPY_AND_ASSIGN(VideoCaptureIndicator); +}; + +} // namespace vr_shell + +#endif // CHROME_BROWSER_ANDROID_VR_SHELL_UI_ELEMENTS_VIDEO_CAPTURE_INDICATOR_H_
diff --git a/chrome/browser/android/vr_shell/ui_scene_manager.cc b/chrome/browser/android/vr_shell/ui_scene_manager.cc index 378aa7d8..0747344 100644 --- a/chrome/browser/android/vr_shell/ui_scene_manager.cc +++ b/chrome/browser/android/vr_shell/ui_scene_manager.cc
@@ -7,12 +7,14 @@ #include "base/callback.h" #include "base/memory/ptr_util.h" #include "chrome/browser/android/vr_shell/textures/ui_texture.h" +#include "chrome/browser/android/vr_shell/ui_elements/audio_capture_indicator.h" #include "chrome/browser/android/vr_shell/ui_elements/close_button.h" #include "chrome/browser/android/vr_shell/ui_elements/loading_indicator.h" #include "chrome/browser/android/vr_shell/ui_elements/permanent_security_warning.h" #include "chrome/browser/android/vr_shell/ui_elements/transient_security_warning.h" #include "chrome/browser/android/vr_shell/ui_elements/ui_element.h" #include "chrome/browser/android/vr_shell/ui_elements/url_bar.h" +#include "chrome/browser/android/vr_shell/ui_elements/video_capture_indicator.h" #include "chrome/browser/android/vr_shell/ui_scene.h" #include "chrome/browser/android/vr_shell/vr_browser_interface.h" #include "chrome/browser/android/vr_shell/vr_shell.h" @@ -65,6 +67,7 @@ CreateBackground(); CreateContentQuad(); CreateSecurityWarnings(); + CreateSystemIndicators(); CreateUrlBar(); if (in_cct_) CreateCloseButton(); @@ -107,6 +110,28 @@ scene_->AddUiElement(std::move(element)); } +void UiSceneManager::CreateSystemIndicators() { + std::unique_ptr<UiElement> element; + + // TODO(acondor): Make constants for sizes and positions once the UX for the + // indicators is defined. + element = base::MakeUnique<AudioCaptureIndicator>(256); + element->set_id(AllocateId()); + element->set_translation({-0.3, 0.8, -1.9}); + element->set_size({0.4, 0, 1}); + element->set_visible(false); + audio_input_indicator_ = element.get(); + scene_->AddUiElement(std::move(element)); + + element = base::MakeUnique<VideoCaptureIndicator>(256); + element->set_id(AllocateId()); + element->set_translation({0.3, 0.8, -1.9}); + element->set_size({0.4, 0, 1}); + element->set_visible(false); + video_input_indicator_ = element.get(); + scene_->AddUiElement(std::move(element)); +} + void UiSceneManager::CreateContentQuad() { std::unique_ptr<UiElement> element;
diff --git a/chrome/browser/android/vr_shell/ui_scene_manager.h b/chrome/browser/android/vr_shell/ui_scene_manager.h index 81e7f5e5..ef917ad5 100644 --- a/chrome/browser/android/vr_shell/ui_scene_manager.h +++ b/chrome/browser/android/vr_shell/ui_scene_manager.h
@@ -46,6 +46,7 @@ private: void CreateSecurityWarnings(); + void CreateSystemIndicators(); void CreateContentQuad(); void CreateBackground(); void CreateUrlBar(); @@ -65,6 +66,8 @@ UiElement* permanent_security_warning_ = nullptr; UiElement* transient_security_warning_ = nullptr; UiElement* main_content_ = nullptr; + UiElement* audio_input_indicator_ = nullptr; + UiElement* video_input_indicator_ = nullptr; UrlBar* url_bar_ = nullptr; LoadingIndicator* loading_indicator_ = nullptr;
diff --git a/chrome/browser/apps/drive/drive_service_bridge.cc b/chrome/browser/apps/drive/drive_service_bridge.cc index 648aa2933..484a54a62 100644 --- a/chrome/browser/apps/drive/drive_service_bridge.cc +++ b/chrome/browser/apps/drive/drive_service_bridge.cc
@@ -9,7 +9,7 @@ #include "base/logging.h" #include "base/macros.h" -#include "base/threading/sequenced_worker_pool.h" +#include "base/task_scheduler/post_task.h" #include "chrome/browser/drive/drive_notification_manager_factory.h" #include "chrome/browser/profiles/profile.h" #include "chrome/browser/signin/profile_oauth2_token_service_factory.h" @@ -20,7 +20,6 @@ #include "components/drive/service/drive_api_service.h" #include "components/signin/core/browser/profile_oauth2_token_service.h" #include "components/signin/core/browser/signin_manager.h" -#include "content/public/browser/browser_thread.h" #include "net/traffic_annotation/network_traffic_annotation.h" namespace { @@ -72,12 +71,10 @@ } void DriveServiceBridgeImpl::Initialize() { - scoped_refptr<base::SequencedWorkerPool> worker_pool( - content::BrowserThread::GetBlockingPool()); scoped_refptr<base::SequencedTaskRunner> drive_task_runner( - worker_pool->GetSequencedTaskRunnerWithShutdownBehavior( - worker_pool->GetSequenceToken(), - base::SequencedWorkerPool::SKIP_ON_SHUTDOWN)); + base::CreateSequencedTaskRunnerWithTraits( + {base::MayBlock(), base::TaskPriority::BACKGROUND, + base::TaskShutdownBehavior::SKIP_ON_SHUTDOWN})); ProfileOAuth2TokenService* token_service = ProfileOAuth2TokenServiceFactory::GetForProfile(profile_);
diff --git a/chrome/browser/autofill/validation_rules_storage_factory.cc b/chrome/browser/autofill/validation_rules_storage_factory.cc index 8265c58..6c6d741 100644 --- a/chrome/browser/autofill/validation_rules_storage_factory.cc +++ b/chrome/browser/autofill/validation_rules_storage_factory.cc
@@ -6,11 +6,9 @@ #include "base/files/file_path.h" #include "base/path_service.h" -#include "base/threading/sequenced_worker_pool.h" #include "chrome/common/chrome_paths.h" #include "components/prefs/json_pref_store.h" #include "components/prefs/pref_filter.h" -#include "content/public/browser/browser_thread.h" #include "third_party/libaddressinput/chromium/chrome_storage_impl.h" namespace autofill { @@ -30,15 +28,8 @@ bool success = PathService::Get(chrome::DIR_USER_DATA, &user_data_dir); DCHECK(success); - base::FilePath cache = - user_data_dir.Append(FILE_PATH_LITERAL("Address Validation Rules")); - - scoped_refptr<base::SequencedTaskRunner> task_runner = - JsonPrefStore::GetTaskRunnerForFile( - cache, content::BrowserThread::GetBlockingPool()); - - json_pref_store_ = new JsonPrefStore(cache, task_runner.get(), - std::unique_ptr<PrefFilter>()); + json_pref_store_ = new JsonPrefStore( + user_data_dir.Append(FILE_PATH_LITERAL("Address Validation Rules"))); json_pref_store_->ReadPrefsAsync(NULL); }
diff --git a/chrome/browser/chrome_content_browser_client.cc b/chrome/browser/chrome_content_browser_client.cc index 00d589b5..0738496b 100644 --- a/chrome/browser/chrome_content_browser_client.cc +++ b/chrome/browser/chrome_content_browser_client.cc
@@ -143,7 +143,7 @@ #include "components/rappor/public/rappor_utils.h" #include "components/rappor/rappor_recorder_impl.h" #include "components/rappor/rappor_service_impl.h" -#include "components/safe_browsing_db/safe_browsing_prefs.h" +#include "components/safe_browsing/common/safe_browsing_prefs.h" #include "components/security_interstitials/core/ssl_error_ui.h" #include "components/signin/core/common/profile_management_switches.h" #include "components/spellcheck/spellcheck_build_features.h"
diff --git a/chrome/browser/chromeos/accessibility/event_handler_common.cc b/chrome/browser/chromeos/accessibility/event_handler_common.cc index d1da17a1..efadb10b 100644 --- a/chrome/browser/chromeos/accessibility/event_handler_common.cc +++ b/chrome/browser/chromeos/accessibility/event_handler_common.cc
@@ -49,6 +49,7 @@ } const content::NativeWebKeyboardEvent web_event(key_event); + // Don't forward latency info, as these are getting forwarded to an extension. rvh->GetWidget()->ForwardKeyboardEvent(web_event); } } // namespace chromeos
diff --git a/chrome/browser/chromeos/arc/process/arc_process.cc b/chrome/browser/chromeos/arc/process/arc_process.cc index 6bafc72..fbb8d7c 100644 --- a/chrome/browser/chromeos/arc/process/arc_process.cc +++ b/chrome/browser/chromeos/arc/process/arc_process.cc
@@ -8,15 +8,6 @@ namespace arc { -namespace { - -// A special process on Android side which serves as a dummy "focused" app -// when the focused window is a Chrome side window (i.e., all Android -// processes are running in the background). We don't want to kill it anyway. -constexpr char kArcHomeProcess[] = "org.chromium.arc.home"; - -} // namespace - ArcProcess::ArcProcess(base::ProcessId nspid, base::ProcessId pid, const std::string& process_name, @@ -44,16 +35,14 @@ ArcProcess& ArcProcess::operator=(ArcProcess&& other) = default; bool ArcProcess::IsImportant() const { - return process_state() <= mojom::ProcessState::IMPORTANT_FOREGROUND || - process_name() == kArcHomeProcess; + return process_state() <= mojom::ProcessState::IMPORTANT_FOREGROUND; } bool ArcProcess::IsKernelKillable() const { // Protect PERSISTENT, PERSISTENT_UI, and our HOME processes since they should // never be killed even by the kernel. Returning false for them allows their // OOM adjustment scores to remain negative. - return process_state() > arc::mojom::ProcessState::PERSISTENT_UI && - process_name() != kArcHomeProcess; + return process_state() > arc::mojom::ProcessState::PERSISTENT_UI; } } // namespace arc
diff --git a/chrome/browser/chromeos/arc/process/arc_process_unittest.cc b/chrome/browser/chromeos/arc/process/arc_process_unittest.cc index aea2d2bc..b351dbef5 100644 --- a/chrome/browser/chromeos/arc/process/arc_process_unittest.cc +++ b/chrome/browser/chromeos/arc/process/arc_process_unittest.cc
@@ -120,15 +120,6 @@ EXPECT_FALSE(ArcProcess(0, 0, "process", mojom::ProcessState::CACHED_EMPTY, kIsNotFocused, 0) .IsImportant()); - - // Exceptions: the function always returns true ignoring ProcessState for our - // HOME process. - EXPECT_TRUE(ArcProcess(0, 0, "org.chromium.arc.home", - mojom::ProcessState::TOP, kIsNotFocused, 0) - .IsImportant()); - EXPECT_TRUE(ArcProcess(0, 0, "org.chromium.arc.home", - mojom::ProcessState::HOME, kIsNotFocused, 0) - .IsImportant()); } TEST(ArcProcess, TestIsKernelKillable) { @@ -196,15 +187,6 @@ EXPECT_TRUE(ArcProcess(0, 0, "process", mojom::ProcessState::CACHED_EMPTY, kIsNotFocused, 0) .IsKernelKillable()); - - // Exceptions: the function always returns false ignoring ProcessState for our - // HOME process. - EXPECT_FALSE(ArcProcess(0, 0, "org.chromium.arc.home", - mojom::ProcessState::TOP, kIsNotFocused, 0) - .IsKernelKillable()); - EXPECT_FALSE(ArcProcess(0, 0, "org.chromium.arc.home", - mojom::ProcessState::HOME, kIsNotFocused, 0) - .IsKernelKillable()); } } // namespace
diff --git a/chrome/browser/download/download_browsertest.cc b/chrome/browser/download/download_browsertest.cc index c627089d..3bdf61d 100644 --- a/chrome/browser/download/download_browsertest.cc +++ b/chrome/browser/download/download_browsertest.cc
@@ -81,8 +81,8 @@ #include "components/infobars/core/confirm_infobar_delegate.h" #include "components/infobars/core/infobar.h" #include "components/prefs/pref_service.h" +#include "components/safe_browsing/common/safe_browsing_prefs.h" #include "components/safe_browsing/csd.pb.h" -#include "components/safe_browsing_db/safe_browsing_prefs.h" #include "content/public/browser/download_danger_type.h" #include "content/public/browser/download_interrupt_reasons.h" #include "content/public/browser/download_item.h"
diff --git a/chrome/browser/extensions/BUILD.gn b/chrome/browser/extensions/BUILD.gn index 7ac9d43..9c7ccd5 100644 --- a/chrome/browser/extensions/BUILD.gn +++ b/chrome/browser/extensions/BUILD.gn
@@ -858,8 +858,8 @@ "//components/proxy_config", "//components/rappor", "//components/resources", + "//components/safe_browsing/common:safe_browsing_prefs", "//components/safe_browsing_db:database_manager", - "//components/safe_browsing_db:safe_browsing_prefs", "//components/safe_json", "//components/search_engines", "//components/sessions",
diff --git a/chrome/browser/extensions/api/preference/preference_api.cc b/chrome/browser/extensions/api/preference/preference_api.cc index 2a4b642..87d9428 100644 --- a/chrome/browser/extensions/api/preference/preference_api.cc +++ b/chrome/browser/extensions/api/preference/preference_api.cc
@@ -32,7 +32,7 @@ #include "components/password_manager/core/common/password_manager_pref_names.h" #include "components/prefs/pref_service.h" #include "components/proxy_config/proxy_config_pref_names.h" -#include "components/safe_browsing_db/safe_browsing_prefs.h" +#include "components/safe_browsing/common/safe_browsing_prefs.h" #include "components/spellcheck/browser/pref_names.h" #include "components/translate/core/browser/translate_pref_names.h" #include "content/public/browser/notification_details.h"
diff --git a/chrome/browser/extensions/api/settings_private/prefs_util.cc b/chrome/browser/extensions/api/settings_private/prefs_util.cc index 6a274bf..21fbe30 100644 --- a/chrome/browser/extensions/api/settings_private/prefs_util.cc +++ b/chrome/browser/extensions/api/settings_private/prefs_util.cc
@@ -19,7 +19,7 @@ #include "components/password_manager/core/common/password_manager_pref_names.h" #include "components/prefs/pref_service.h" #include "components/proxy_config/proxy_config_pref_names.h" -#include "components/safe_browsing_db/safe_browsing_prefs.h" +#include "components/safe_browsing/common/safe_browsing_prefs.h" #include "components/search_engines/default_search_manager.h" #include "components/spellcheck/browser/pref_names.h" #include "components/translate/core/browser/translate_pref_names.h"
diff --git a/chrome/browser/interstitials/chrome_controller_client.cc b/chrome/browser/interstitials/chrome_controller_client.cc index 5da412d..7c46a06 100644 --- a/chrome/browser/interstitials/chrome_controller_client.cc +++ b/chrome/browser/interstitials/chrome_controller_client.cc
@@ -14,7 +14,7 @@ #include "chrome/browser/profiles/profile.h" #include "chrome/common/pref_names.h" #include "chrome/common/url_constants.h" -#include "components/safe_browsing_db/safe_browsing_prefs.h" +#include "components/safe_browsing/common/safe_browsing_prefs.h" #include "content/public/browser/browser_thread.h" #include "content/public/browser/web_contents.h"
diff --git a/chrome/browser/io_thread.cc b/chrome/browser/io_thread.cc index b92436f..6ef847c 100644 --- a/chrome/browser/io_thread.cc +++ b/chrome/browser/io_thread.cc
@@ -108,6 +108,7 @@ #include "net/url_request/url_request_context.h" #include "net/url_request/url_request_context_builder.h" #include "net/url_request/url_request_context_getter.h" +#include "net/url_request/url_request_context_storage.h" #include "net/url_request/url_request_job_factory_impl.h" #include "url/url_constants.h" @@ -197,13 +198,19 @@ #endif } - private: ~SystemURLRequestContext() override { AssertNoURLRequests(); #if defined(USE_NSS_CERTS) net::SetURLRequestContextForNSSHttpIO(NULL); #endif + +#if defined(OS_ANDROID) + net::CertVerifyProcAndroid::ShutdownCertNetFetcher(); +#endif } + + private: + DISALLOW_COPY_AND_ASSIGN(SystemURLRequestContext); }; std::unique_ptr<net::HostResolver> CreateGlobalHostResolver( @@ -396,6 +403,8 @@ pref_proxy_config_tracker_.reset( ProxyServiceFactory::CreatePrefProxyConfigTrackerOfLocalState( local_state)); + system_proxy_config_service_ = ProxyServiceFactory::CreateProxyConfigService( + pref_proxy_config_tracker_.get()); ChromeNetworkDelegate::InitializePrefsOnUIThread( &system_enable_referrers_, nullptr, @@ -487,7 +496,8 @@ net::URLRequestContextGetter* IOThread::system_url_request_context_getter() { DCHECK_CURRENTLY_ON(BrowserThread::UI); if (!system_url_request_context_getter_.get()) { - InitSystemRequestContext(); + system_url_request_context_getter_ = + new SystemURLRequestContextGetter(this); } return system_url_request_context_getter_.get(); } @@ -631,14 +641,6 @@ // For the ProxyScriptFetcher, we use a direct ProxyService. globals_->proxy_script_fetcher_proxy_service = net::ProxyService::CreateDirectWithNetLog(net_log_); - // In-memory cookie store. - globals_->system_cookie_store = - content::CreateCookieStore(content::CookieStoreConfig()); - // In-memory channel ID store. - globals_->system_channel_id_service.reset( - new net::ChannelIDService(new net::DefaultChannelIDStore(NULL))); - globals_->system_cookie_store->SetChannelIDServiceID( - globals_->system_channel_id_service->GetUniqueID()); globals_->dns_probe_service.reset(new chrome_browser_net::DnsProbeService()); globals_->host_mapping_rules.reset(new net::HostMappingRules()); params_.host_mapping_rules = globals_->host_mapping_rules.get(); @@ -668,13 +670,6 @@ command_line, is_quic_allowed_by_policy_, http_09_on_non_default_ports_enabled_, ¶ms_); - TRACE_EVENT_BEGIN0("startup", - "IOThread::Init:ProxyScriptFetcherRequestContext"); - globals_->proxy_script_fetcher_context.reset( - ConstructProxyScriptFetcherContext(globals_, params_, net_log_)); - TRACE_EVENT_END0("startup", - "IOThread::Init:ProxyScriptFetcherRequestContext"); - #if defined(OS_MACOSX) // Start observing Keychain events. This needs to be done on the UI thread, // as Keychain services requires a CFRunLoop. @@ -683,26 +678,14 @@ base::Bind(&ObserveKeychainEvents)); #endif - // InitSystemRequestContext turns right around and posts a task back - // to the IO thread, so we can't let it run until we know the IO - // thread has started. - // - // Note that since we are at BrowserThread::Init time, the UI thread - // is blocked waiting for the thread to start. Therefore, posting - // this task to the main thread's message loop here is guaranteed to - // get it onto the message loop while the IOThread object still - // exists. However, the message might not be processed on the UI - // thread until after IOThread is gone, so use a weak pointer. - BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, - base::BindOnce(&IOThread::InitSystemRequestContext, - weak_factory_.GetWeakPtr())); - #if defined(OS_ANDROID) && defined(ARCH_CPU_ARMEL) // Record how common CPUs with broken NEON units are. See // https://crbug.com/341598. crypto::EnsureOpenSSLInit(); UMA_HISTOGRAM_BOOLEAN("Net.HasBrokenNEON", CRYPTO_has_broken_NEON()); #endif + + ConstructSystemRequestContext(); } void IOThread::CleanUp() { @@ -712,19 +695,19 @@ net::ShutdownNSSHttpIO(); #endif -#if defined(OS_ANDROID) - net::CertVerifyProcAndroid::ShutdownCertNetFetcher(); -#endif - system_url_request_context_getter_ = NULL; // Unlink the ct_tree_tracker_ from the global cert_transparency_verifier // and unregister it from new STH notifications so it will take no actions // on anything observed during CleanUp process. - globals()->cert_transparency_verifier->SetObserver(nullptr); - UnregisterSTHObserver(ct_tree_tracker_.get()); - - ct_tree_tracker_.reset(); + // + // Null checks are just for tests that use TestingIOThreadState. + if (globals()->cert_transparency_verifier) + globals()->cert_transparency_verifier->SetObserver(nullptr); + if (ct_tree_tracker_.get()) { + UnregisterSTHObserver(ct_tree_tracker_.get()); + ct_tree_tracker_.reset(); + } // Release objects that the net::URLRequestContext could have been pointing // to. @@ -830,8 +813,9 @@ void IOThread::DisableQuic() { params_.enable_quic = false; - if (globals_->system_http_network_session) - globals_->system_http_network_session->DisableQuic(); + if (globals_->system_request_context_storage) + globals_->system_request_context_storage->http_network_session() + ->DisableQuic(); if (globals_->proxy_script_fetcher_http_network_session) globals_->proxy_script_fetcher_http_network_session->DisableQuic(); @@ -853,41 +837,6 @@ ClearHostCache(base::Callback<bool(const std::string&)>()); } -void IOThread::InitSystemRequestContext() { - if (system_url_request_context_getter_.get()) - return; - // If we're in unit_tests, IOThread may not be run. - if (!BrowserThread::IsMessageLoopValid(BrowserThread::IO)) - return; - system_proxy_config_service_ = ProxyServiceFactory::CreateProxyConfigService( - pref_proxy_config_tracker_.get()); - system_url_request_context_getter_ = - new SystemURLRequestContextGetter(this); - // Safe to post an unretained this pointer, since IOThread is - // guaranteed to outlive the IO BrowserThread. - BrowserThread::PostTask( - BrowserThread::IO, FROM_HERE, - base::BindOnce(&IOThread::InitSystemRequestContextOnIOThread, - base::Unretained(this))); -} - -void IOThread::InitSystemRequestContextOnIOThread() { - DCHECK_CURRENTLY_ON(BrowserThread::IO); - DCHECK(!globals_->system_proxy_service.get()); - DCHECK(system_proxy_config_service_.get()); - - const base::CommandLine& command_line = - *base::CommandLine::ForCurrentProcess(); - globals_->system_proxy_service = ProxyServiceFactory::CreateProxyService( - net_log_, globals_->proxy_script_fetcher_context.get(), - globals_->system_network_delegate.get(), - std::move(system_proxy_config_service_), command_line, - WpadQuickCheckEnabled(), PacHttpsUrlStrippingEnabled()); - - globals_->system_request_context.reset( - ConstructSystemRequestContext(globals_, params_, net_log_)); -} - void IOThread::UpdateDnsClientEnabled() { globals()->host_resolver->SetDnsClientEnabled(*dns_client_enabled_); } @@ -908,58 +857,77 @@ return pac_https_url_stripping_enabled_.GetValue(); } -// static -net::URLRequestContext* IOThread::ConstructSystemRequestContext( - IOThread::Globals* globals, - const net::HttpNetworkSession::Params& params, - net::NetLog* net_log) { - net::URLRequestContext* context = new SystemURLRequestContext; +void IOThread::ConstructSystemRequestContext() { + globals_->system_request_context = + base::MakeUnique<SystemURLRequestContext>(); + net::URLRequestContext* context = globals_->system_request_context.get(); + globals_->system_request_context_storage = + base::MakeUnique<net::URLRequestContextStorage>(context); + net::URLRequestContextStorage* context_storage = + globals_->system_request_context_storage.get(); context->set_network_quality_estimator( - globals->network_quality_estimator.get()); - context->set_enable_brotli(globals->enable_brotli); + globals_->network_quality_estimator.get()); + context->set_enable_brotli(globals_->enable_brotli); context->set_name("system"); context->set_http_user_agent_settings( - globals->http_user_agent_settings.get()); - context->set_network_delegate(globals->system_network_delegate.get()); - context->set_net_log(net_log); - context->set_host_resolver(globals->host_resolver.get()); - context->set_proxy_service(globals->system_proxy_service.get()); - context->set_ssl_config_service(globals->ssl_config_service.get()); + globals_->http_user_agent_settings.get()); + context->set_network_delegate(globals_->system_network_delegate.get()); + context->set_net_log(net_log_); + context->set_host_resolver(globals_->host_resolver.get()); + + context->set_ssl_config_service(globals_->ssl_config_service.get()); context->set_http_auth_handler_factory( - globals->http_auth_handler_factory.get()); + globals_->http_auth_handler_factory.get()); - context->set_cookie_store(globals->system_cookie_store.get()); - context->set_channel_id_service( - globals->system_channel_id_service.get()); + // In-memory cookie store. + context_storage->set_cookie_store( + content::CreateCookieStore(content::CookieStoreConfig())); + // In-memory channel ID store. + context_storage->set_channel_id_service( + base::MakeUnique<net::ChannelIDService>( + new net::DefaultChannelIDStore(nullptr))); + context->cookie_store()->SetChannelIDServiceID( + context->channel_id_service()->GetUniqueID()); + context->set_transport_security_state( - globals->transport_security_state.get()); + globals_->transport_security_state.get()); - context->set_http_server_properties(globals->http_server_properties.get()); + context->set_http_server_properties(globals_->http_server_properties.get()); - context->set_cert_verifier(globals->cert_verifier.get()); + context->set_cert_verifier(globals_->cert_verifier.get()); context->set_cert_transparency_verifier( - globals->cert_transparency_verifier.get()); - context->set_ct_policy_enforcer(globals->ct_policy_enforcer.get()); + globals_->cert_transparency_verifier.get()); + context->set_ct_policy_enforcer(globals_->ct_policy_enforcer.get()); - net::HttpNetworkSession::Params system_params(params); + TRACE_EVENT_BEGIN0("startup", + "IOThread::Init:ProxyScriptFetcherRequestContext"); + globals_->proxy_script_fetcher_context.reset( + ConstructProxyScriptFetcherContext(globals_, params_, net_log_)); + TRACE_EVENT_END0("startup", + "IOThread::Init:ProxyScriptFetcherRequestContext"); + + const base::CommandLine& command_line = + *base::CommandLine::ForCurrentProcess(); + context_storage->set_proxy_service(ProxyServiceFactory::CreateProxyService( + net_log_, globals_->proxy_script_fetcher_context.get(), + globals_->system_network_delegate.get(), + std::move(system_proxy_config_service_), command_line, + WpadQuickCheckEnabled(), PacHttpsUrlStrippingEnabled())); + + net::HttpNetworkSession::Params system_params(params_); net::URLRequestContextBuilder::SetHttpNetworkSessionComponents( context, &system_params); - globals->system_http_network_session.reset( - new net::HttpNetworkSession(system_params)); - globals->system_http_transaction_factory.reset( - new net::HttpNetworkLayer(globals->system_http_network_session.get())); + context_storage->set_http_network_session( + base::MakeUnique<net::HttpNetworkSession>(system_params)); + context_storage->set_http_transaction_factory( + base::MakeUnique<net::HttpNetworkLayer>( + context_storage->http_network_session())); - context->set_http_transaction_factory( - globals->system_http_transaction_factory.get()); - - globals->system_url_request_job_factory.reset( - new net::URLRequestJobFactoryImpl()); - context->set_job_factory(globals->system_url_request_job_factory.get()); - - return context; + context_storage->set_job_factory( + base::MakeUnique<net::URLRequestJobFactoryImpl>()); } // static @@ -1078,9 +1046,9 @@ context->set_job_factory( globals->proxy_script_fetcher_url_request_job_factory.get()); - context->set_cookie_store(globals->system_cookie_store.get()); + context->set_cookie_store(globals->system_request_context->cookie_store()); context->set_channel_id_service( - globals->system_channel_id_service.get()); + globals->system_request_context->channel_id_service()); context->set_network_delegate(globals->system_network_delegate.get()); context->set_http_user_agent_settings( globals->http_user_agent_settings.get());
diff --git a/chrome/browser/io_thread.h b/chrome/browser/io_thread.h index a1069e3f..4b83d2b 100644 --- a/chrome/browser/io_thread.h +++ b/chrome/browser/io_thread.h
@@ -37,7 +37,6 @@ class PrefProxyConfigTracker; class PrefService; class PrefRegistrySimple; -class SystemURLRequestContextGetter; #if defined(OS_ANDROID) namespace chrome { @@ -55,6 +54,10 @@ class TreeStateTracker; } +namespace chrome { +class TestingIOThreadState; +} + namespace chrome_browser_net { class DnsProbeService; } @@ -74,8 +77,6 @@ namespace net { class CTPolicyEnforcer; class CertVerifier; -class ChannelIDService; -class CookieStore; class CTLogVerifier; class HostMappingRules; class HostResolver; @@ -92,6 +93,7 @@ class TransportSecurityState; class URLRequestContext; class URLRequestContextGetter; +class URLRequestContextStorage; class URLRequestJobFactory; namespace ct { @@ -148,8 +150,6 @@ std::unique_ptr<net::NetworkDelegate> system_network_delegate; std::unique_ptr<net::HostResolver> host_resolver; std::unique_ptr<net::CertVerifier> cert_verifier; - // The ChannelIDService must outlive the HttpTransactionFactory. - std::unique_ptr<net::ChannelIDService> system_channel_id_service; // This TransportSecurityState doesn't load or save any state. It's only // used to enforce pinning for system requests and will only use built-in // pins. @@ -175,16 +175,10 @@ // |proxy_script_fetcher_context| for the second context. It has a direct // ProxyService, since we always directly connect to fetch the PAC script. std::unique_ptr<net::URLRequestContext> proxy_script_fetcher_context; - std::unique_ptr<net::ProxyService> system_proxy_service; - std::unique_ptr<net::HttpNetworkSession> system_http_network_session; - std::unique_ptr<net::HttpTransactionFactory> - system_http_transaction_factory; - std::unique_ptr<net::URLRequestJobFactory> system_url_request_job_factory; + std::unique_ptr<net::URLRequestContextStorage> + system_request_context_storage; std::unique_ptr<net::URLRequestContext> system_request_context; SystemRequestContextLeakChecker system_request_context_leak_checker; - // |system_cookie_store| and |system_channel_id_service| are shared - // between |proxy_script_fetcher_context| and |system_request_context|. - std::unique_ptr<net::CookieStore> system_cookie_store; #if BUILDFLAG(ENABLE_EXTENSIONS) scoped_refptr<extensions::EventRouterForwarder> extension_event_router_forwarder; @@ -269,11 +263,8 @@ bool PacHttpsUrlStrippingEnabled() const; private: - // Provide SystemURLRequestContextGetter with access to - // InitSystemRequestContext(). - friend class SystemURLRequestContextGetter; - friend class test::IOThreadPeer; + friend class chrome::TestingIOThreadState; // BrowserThreadDelegate implementation, runs on the IO thread. // This handles initialization and destruction of state that must @@ -281,16 +272,6 @@ void Init() override; void CleanUp() override; - // Global state must be initialized on the IO thread, then this - // method must be invoked on the UI thread. - void InitSystemRequestContext(); - - // Lazy initialization of system request context for - // SystemURLRequestContextGetter. To be called on IO thread only - // after global state has been initialized on the IO thread, and - // SystemRequestContext state has been initialized on the UI thread. - void InitSystemRequestContextOnIOThread(); - void CreateDefaultAuthHandlerFactory(); // Returns an SSLConfigService instance. @@ -312,10 +293,7 @@ return NULL; #endif } - static net::URLRequestContext* ConstructSystemRequestContext( - IOThread::Globals* globals, - const net::HttpNetworkSession::Params& params, - net::NetLog* net_log); + void ConstructSystemRequestContext(); // Parse command line flags and use components/network_session_configurator to // configure |params|.
diff --git a/chrome/browser/net/predictor.cc b/chrome/browser/net/predictor.cc index 2bb7698..5d73b27 100644 --- a/chrome/browser/net/predictor.cc +++ b/chrome/browser/net/predictor.cc
@@ -242,17 +242,19 @@ const GURL& first_party_for_cookies) { DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI) || BrowserThread::CurrentlyOn(BrowserThread::IO)); - if (!PredictorEnabled() || !url.is_valid() || - !url.has_host()) + if (!PredictorEnabled()) return; if (!CanPreresolveAndPreconnect()) return; - + const GURL canonicalized_url = CanonicalizeUrl(url); + if (!canonicalized_url.is_valid() || !canonicalized_url.has_host()) + return; UrlInfo::ResolutionMotivation motivation(UrlInfo::EARLY_LOAD_MOTIVATED); const int kConnectionsNeeded = 1; - PreconnectUrl(CanonicalizeUrl(url), first_party_for_cookies, motivation, + PreconnectUrl(canonicalized_url, first_party_for_cookies, motivation, kConnectionsNeeded, kAllowCredentialsOnPreconnectByDefault); - PredictFrameSubresources(url.GetWithEmptyPath(), first_party_for_cookies); + PredictFrameSubresources(canonicalized_url.GetWithEmptyPath(), + first_party_for_cookies); } std::vector<GURL> Predictor::GetPredictedUrlListAtStartup( @@ -725,6 +727,7 @@ int count) { DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI) || BrowserThread::CurrentlyOn(BrowserThread::IO)); + DCHECK(url.is_valid()); if (BrowserThread::CurrentlyOn(BrowserThread::IO)) { PreconnectUrlOnIOThread(url, first_party_for_cookies, motivation,
diff --git a/chrome/browser/net/predictor_browsertest.cc b/chrome/browser/net/predictor_browsertest.cc index 7df1e68..add17de9 100644 --- a/chrome/browser/net/predictor_browsertest.cc +++ b/chrome/browser/net/predictor_browsertest.cc
@@ -321,6 +321,7 @@ chrome_browser_net::UrlInfo::ResolutionMotivation motivation, int count) override { base::AutoLock lock(lock_); + preconnect_url_attempts_.insert(original_url); if (original_url == cross_site_host_) { cross_site_preconnected_ = std::max(cross_site_preconnected_, count); } else if (original_url == source_host_) { @@ -412,6 +413,11 @@ return HasHostBeenLookedUpLocked(url); } + bool HasHostAttemptedToPreconnect(const GURL& url) { + base::AutoLock lock(lock_); + return base::ContainsKey(preconnect_url_attempts_, url); + } + void CheckForWaitingLoop() { lock_.AssertAcquired(); if (waiting_on_dns_.is_empty()) @@ -466,6 +472,7 @@ int cross_site_preconnected_; int same_site_preconnected_; + std::set<GURL> preconnect_url_attempts_; std::set<GURL> successful_dns_lookups_; std::set<GURL> unsuccessful_dns_lookups_; base::RunLoop* dns_run_loop_; @@ -876,6 +883,18 @@ connection_listener_->WaitForAcceptedConnectionsOnUI(4u); } +// Regression test for crbug.com/721981. +IN_PROC_BROWSER_TEST_F(PredictorBrowserTest, PreconnectNonHttpScheme) { + GURL url("chrome-native://dummyurl"); + predictor()->PreconnectUrlAndSubresources(url, GURL()); + base::RunLoop().RunUntilIdle(); + // Since |url| is non-HTTP(s) scheme, Predictor will canonicalize it to an + // empty url. Make sure that there is no attempt to preconnect |url| or an + // empty url. + EXPECT_FALSE(observer()->HasHostAttemptedToPreconnect(url)); + EXPECT_FALSE(observer()->HasHostAttemptedToPreconnect(GURL())); +} + // Test the html test harness used to initiate cross site fetches. These // initiate cross site subresource requests to the cross site test server. // Inspect the predictor's internal state to make sure that they are properly
diff --git a/chrome/browser/page_load_metrics/observers/ads_page_load_metrics_observer.cc b/chrome/browser/page_load_metrics/observers/ads_page_load_metrics_observer.cc index cb4ad34..b1b2c49 100644 --- a/chrome/browser/page_load_metrics/observers/ads_page_load_metrics_observer.cc +++ b/chrome/browser/page_load_metrics/observers/ads_page_load_metrics_observer.cc
@@ -117,8 +117,6 @@ UMA_HISTOGRAM_BOOLEAN( "PageLoad.Clients.Ads.Google.Navigations.NonAdFrameRenavigatedToAd", FrameIsAd(navigation_handle)); - } else if (navigation_handle->IsParentMainFrame()) { - top_level_subframe_count_ += 1; } // Determine who the parent frame's ad ancestor is. @@ -135,9 +133,6 @@ ad_frames_data_[frame_tree_node_id] = ad_data; - if (navigation_handle->IsParentMainFrame() && ad_data) - top_level_ad_frame_count_ += 1; - ProcessOngoingNavigationResource(frame_tree_node_id); return CONTINUE_OBSERVING; } @@ -215,18 +210,15 @@ if (page_bytes_ == 0) return; + int non_zero_ad_frames = 0; size_t total_ad_frame_bytes = 0; size_t uncached_ad_frame_bytes = 0; - UMA_HISTOGRAM_COUNTS_1000( - "PageLoad.Clients.Ads.Google.FrameCounts.AnyParentFrame.AdFrames", - ad_frames_data_storage_.size()); - - // Don't post UMA for pages that don't have ads. - if (ad_frames_data_storage_.empty()) - return; - for (const AdFrameData& ad_frame_data : ad_frames_data_storage_) { + if (ad_frame_data.frame_bytes == 0) + continue; + + non_zero_ad_frames += 1; total_ad_frame_bytes += ad_frame_data.frame_bytes; uncached_ad_frame_bytes += ad_frame_data.frame_bytes_uncached; @@ -236,24 +228,18 @@ PAGE_BYTES_HISTOGRAM( "PageLoad.Clients.Ads.Google.Bytes.AdFrames.PerFrame.Network", ad_frame_data.frame_bytes_uncached); - if (ad_frame_data.frame_bytes > 0) { - UMA_HISTOGRAM_PERCENTAGE( - "PageLoad.Clients.Ads.Google.Bytes.AdFrames.PerFrame.PercentNetwork", - ad_frame_data.frame_bytes_uncached * 100 / ad_frame_data.frame_bytes); - } + UMA_HISTOGRAM_PERCENTAGE( + "PageLoad.Clients.Ads.Google.Bytes.AdFrames.PerFrame.PercentNetwork", + ad_frame_data.frame_bytes_uncached * 100 / ad_frame_data.frame_bytes); } UMA_HISTOGRAM_COUNTS_1000( - "PageLoad.Clients.Ads.Google.FrameCounts.MainFrameParent.TotalFrames", - top_level_subframe_count_); - UMA_HISTOGRAM_COUNTS_1000( - "PageLoad.Clients.Ads.Google.FrameCounts.MainFrameParent.AdFrames", - top_level_ad_frame_count_); + "PageLoad.Clients.Ads.Google.FrameCounts.AnyParentFrame.AdFrames", + non_zero_ad_frames); - DCHECK_LT(0, top_level_subframe_count_); // Because ad frames isn't empty. - UMA_HISTOGRAM_PERCENTAGE( - "PageLoad.Clients.Ads.Google.FrameCounts.MainFrameParent.PercentAdFrames", - top_level_ad_frame_count_ * 100 / top_level_subframe_count_); + // Don't post UMA for pages that don't have ads. + if (non_zero_ad_frames == 0) + return; PAGE_BYTES_HISTOGRAM( "PageLoad.Clients.Ads.Google.Bytes.NonAdFrames.Aggregate.Total",
diff --git a/chrome/browser/page_load_metrics/observers/ads_page_load_metrics_observer.h b/chrome/browser/page_load_metrics/observers/ads_page_load_metrics_observer.h index f51ef0b..af15657 100644 --- a/chrome/browser/page_load_metrics/observers/ads_page_load_metrics_observer.h +++ b/chrome/browser/page_load_metrics/observers/ads_page_load_metrics_observer.h
@@ -73,8 +73,6 @@ size_t page_bytes_ = 0u; size_t uncached_page_bytes_ = 0u; - int top_level_subframe_count_ = 0; - int top_level_ad_frame_count_ = 0; DISALLOW_COPY_AND_ASSIGN(AdsPageLoadMetricsObserver); };
diff --git a/chrome/browser/page_load_metrics/observers/ads_page_load_metrics_observer_unittest.cc b/chrome/browser/page_load_metrics/observers/ads_page_load_metrics_observer_unittest.cc index 79c9fae..c492069 100644 --- a/chrome/browser/page_load_metrics/observers/ads_page_load_metrics_observer_unittest.cc +++ b/chrome/browser/page_load_metrics/observers/ads_page_load_metrics_observer_unittest.cc
@@ -152,14 +152,6 @@ // 20KB total were loaded from network, one of which was in an ad frame. histogram_tester().ExpectUniqueSample( "PageLoad.Clients.Ads.Google.FrameCounts.AnyParentFrame.AdFrames", 1, 1); - histogram_tester().ExpectUniqueSample( - "PageLoad.Clients.Ads.Google.FrameCounts.MainFrameParent.TotalFrames", 1, - 1); - histogram_tester().ExpectUniqueSample( - "PageLoad.Clients.Ads.Google.FrameCounts.MainFrameParent.AdFrames", 1, 1); - histogram_tester().ExpectUniqueSample( - "PageLoad.Clients.Ads.Google.FrameCounts.MainFrameParent.PercentAdFrames", - 100, 1); // Individual Ad Frame Metrics histogram_tester().ExpectUniqueSample( @@ -212,8 +204,8 @@ RenderFrameHost* nested_ad_frame4 = CreateAndNavigateSubFrame( "https://tpc.googlesyndication.com/safeframe/2", "", ad_frame4); - // Create an addditional ad frame without content, it shouldn't be counted - // in some percentage calculations. + // Create an addditional ad frame without content. It shouldn't be counted + // as an ad frame. CreateAndNavigateSubFrame(kAdUrl, kNonAdName, main_frame); // 70KB total in page, 50 from ads, 40 from network, and 30 of those @@ -237,7 +229,7 @@ histogram_tester().ExpectBucketCount( "PageLoad.Clients.Ads.Google.Bytes.AdFrames.PerFrame.Network", 10, 3); histogram_tester().ExpectBucketCount( - "PageLoad.Clients.Ads.Google.Bytes.AdFrames.PerFrame.Network", 0, 2); + "PageLoad.Clients.Ads.Google.Bytes.AdFrames.PerFrame.Network", 0, 1); histogram_tester().ExpectBucketCount( "PageLoad.Clients.Ads.Google.Bytes.AdFrames.PerFrame.PercentNetwork", 0, 1); @@ -250,15 +242,7 @@ // Counts histogram_tester().ExpectUniqueSample( - "PageLoad.Clients.Ads.Google.FrameCounts.AnyParentFrame.AdFrames", 5, 1); - histogram_tester().ExpectUniqueSample( - "PageLoad.Clients.Ads.Google.FrameCounts.MainFrameParent.TotalFrames", 6, - 1); - histogram_tester().ExpectUniqueSample( - "PageLoad.Clients.Ads.Google.FrameCounts.MainFrameParent.AdFrames", 5, 1); - histogram_tester().ExpectUniqueSample( - "PageLoad.Clients.Ads.Google.FrameCounts.MainFrameParent.PercentAdFrames", - 83, 1); + "PageLoad.Clients.Ads.Google.FrameCounts.AnyParentFrame.AdFrames", 4, 1); // Page percentages histogram_tester().ExpectUniqueSample( @@ -349,14 +333,6 @@ // Counts histogram_tester().ExpectUniqueSample( "PageLoad.Clients.Ads.Google.FrameCounts.AnyParentFrame.AdFrames", 1, 1); - histogram_tester().ExpectUniqueSample( - "PageLoad.Clients.Ads.Google.FrameCounts.MainFrameParent.TotalFrames", 1, - 1); - histogram_tester().ExpectUniqueSample( - "PageLoad.Clients.Ads.Google.FrameCounts.MainFrameParent.AdFrames", 1, 1); - histogram_tester().ExpectUniqueSample( - "PageLoad.Clients.Ads.Google.FrameCounts.MainFrameParent.PercentAdFrames", - 100, 1); // Page percentages histogram_tester().ExpectUniqueSample( @@ -419,14 +395,6 @@ // Counts histogram_tester().ExpectUniqueSample( "PageLoad.Clients.Ads.Google.FrameCounts.AnyParentFrame.AdFrames", 2, 1); - histogram_tester().ExpectUniqueSample( - "PageLoad.Clients.Ads.Google.FrameCounts.MainFrameParent.TotalFrames", 1, - 1); - histogram_tester().ExpectUniqueSample( - "PageLoad.Clients.Ads.Google.FrameCounts.MainFrameParent.AdFrames", 1, 1); - histogram_tester().ExpectUniqueSample( - "PageLoad.Clients.Ads.Google.FrameCounts.MainFrameParent.PercentAdFrames", - 100, 1); // Page percentages histogram_tester().ExpectUniqueSample( @@ -560,14 +528,6 @@ // Counts histogram_tester().ExpectUniqueSample( "PageLoad.Clients.Ads.Google.FrameCounts.AnyParentFrame.AdFrames", 1, 1); - histogram_tester().ExpectUniqueSample( - "PageLoad.Clients.Ads.Google.FrameCounts.MainFrameParent.TotalFrames", 1, - 1); - histogram_tester().ExpectUniqueSample( - "PageLoad.Clients.Ads.Google.FrameCounts.MainFrameParent.AdFrames", 1, 1); - histogram_tester().ExpectUniqueSample( - "PageLoad.Clients.Ads.Google.FrameCounts.MainFrameParent.PercentAdFrames", - 100, 1); // Page percentages histogram_tester().ExpectUniqueSample(
diff --git a/chrome/browser/profiles/profile.cc b/chrome/browser/profiles/profile.cc index 0da71217..27d53ff 100644 --- a/chrome/browser/profiles/profile.cc +++ b/chrome/browser/profiles/profile.cc
@@ -17,7 +17,7 @@ #include "components/data_reduction_proxy/core/browser/data_reduction_proxy_prefs.h" #include "components/pref_registry/pref_registry_syncable.h" #include "components/prefs/pref_service.h" -#include "components/safe_browsing_db/safe_browsing_prefs.h" +#include "components/safe_browsing/common/safe_browsing_prefs.h" #include "components/sync/base/sync_prefs.h" #include "content/public/browser/host_zoom_map.h" #include "content/public/browser/notification_service.h"
diff --git a/chrome/browser/safe_browsing/certificate_reporting_service.cc b/chrome/browser/safe_browsing/certificate_reporting_service.cc index f75d1ce..31854c5 100644 --- a/chrome/browser/safe_browsing/certificate_reporting_service.cc +++ b/chrome/browser/safe_browsing/certificate_reporting_service.cc
@@ -12,7 +12,7 @@ #include "chrome/browser/safe_browsing/safe_browsing_service.h" #include "components/certificate_reporting/error_report.h" #include "components/prefs/pref_service.h" -#include "components/safe_browsing_db/safe_browsing_prefs.h" +#include "components/safe_browsing/common/safe_browsing_prefs.h" #include "content/public/browser/browser_thread.h" namespace {
diff --git a/chrome/browser/safe_browsing/chrome_cleaner/chrome_cleaner_dialog_controller.cc b/chrome/browser/safe_browsing/chrome_cleaner/chrome_cleaner_dialog_controller.cc deleted file mode 100644 index a5e6ab2..0000000 --- a/chrome/browser/safe_browsing/chrome_cleaner/chrome_cleaner_dialog_controller.cc +++ /dev/null
@@ -1,67 +0,0 @@ -// Copyright 2017 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. - -#include "chrome/browser/safe_browsing/chrome_cleaner/chrome_cleaner_dialog_controller.h" - -#include "base/strings/utf_string_conversions.h" - -namespace safe_browsing { - -namespace { - -// Some dummy strings to be displayed in the Cleaner dialog while iterating on -// the dialog's UX design and work on the Chrome<->Cleaner IPC is ongoing. -constexpr char kWindowTitle[] = "Clean up your computer?"; -constexpr char kMainText[] = - "Chrome found software that harms your browsing experience. Remove related " - "files from your computer and restore browser settings, including your " - "search engine and home page."; -constexpr char kAcceptButtonLabel[] = "Cleanup"; -constexpr char kAdvancedButtonLabel[] = "Advanced"; - -} // namespace - -ChromeCleanerDialogController::ChromeCleanerDialogController() {} - -ChromeCleanerDialogController::~ChromeCleanerDialogController() = default; - -base::string16 ChromeCleanerDialogController::GetWindowTitle() const { - return base::UTF8ToUTF16(kWindowTitle); -} - -base::string16 ChromeCleanerDialogController::GetMainText() const { - return base::UTF8ToUTF16(kMainText); -} - -base::string16 ChromeCleanerDialogController::GetAcceptButtonLabel() const { - return base::UTF8ToUTF16(kAcceptButtonLabel); -} - -base::string16 ChromeCleanerDialogController::GetAdvancedButtonLabel() const { - return base::UTF8ToUTF16(kAdvancedButtonLabel); -} - -void ChromeCleanerDialogController::DialogShown() {} - -void ChromeCleanerDialogController::Accept() { - OnInteractionDone(); -} - -void ChromeCleanerDialogController::Cancel() { - OnInteractionDone(); -} - -void ChromeCleanerDialogController::Close() { - OnInteractionDone(); -} - -void ChromeCleanerDialogController::AdvancedButtonClicked() { - OnInteractionDone(); -} - -void ChromeCleanerDialogController::OnInteractionDone() { - delete this; -} - -} // namespace safe_browsing
diff --git a/chrome/browser/safe_browsing/chrome_cleaner/chrome_cleaner_dialog_controller_win.cc b/chrome/browser/safe_browsing/chrome_cleaner/chrome_cleaner_dialog_controller_win.cc new file mode 100644 index 0000000..b2bc68bd --- /dev/null +++ b/chrome/browser/safe_browsing/chrome_cleaner/chrome_cleaner_dialog_controller_win.cc
@@ -0,0 +1,57 @@ +// Copyright 2017 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. + +#include "chrome/browser/safe_browsing/chrome_cleaner/chrome_cleaner_dialog_controller_win.h" + +#include "chrome/grit/chromium_strings.h" +#include "chrome/grit/generated_resources.h" +#include "ui/base/l10n/l10n_util.h" + +namespace safe_browsing { + +ChromeCleanerDialogController::ChromeCleanerDialogController() {} + +ChromeCleanerDialogController::~ChromeCleanerDialogController() = default; + +base::string16 ChromeCleanerDialogController::GetWindowTitle() const { + return l10n_util::GetStringUTF16(IDS_CHROME_CLEANUP_PROMPT_TITLE); +} + +base::string16 ChromeCleanerDialogController::GetMainText() const { + return l10n_util::GetStringUTF16(IDS_CHROME_CLEANUP_PROMPT_EXPLANATION); +} + +base::string16 ChromeCleanerDialogController::GetAcceptButtonLabel() const { + return l10n_util::GetStringUTF16( + IDS_CHROME_CLEANUP_PROMPT_REMOVE_BUTTON_LABEL); +} + +base::string16 ChromeCleanerDialogController::GetDetailsButtonLabel() const { + return l10n_util::GetStringUTF16( + IDS_CHROME_CLEANUP_PROMPT_DETAILS_BUTTON_LABEL); +} + +void ChromeCleanerDialogController::DialogShown() {} + +void ChromeCleanerDialogController::Accept() { + OnInteractionDone(); +} + +void ChromeCleanerDialogController::Cancel() { + OnInteractionDone(); +} + +void ChromeCleanerDialogController::Close() { + OnInteractionDone(); +} + +void ChromeCleanerDialogController::DetailsButtonClicked() { + OnInteractionDone(); +} + +void ChromeCleanerDialogController::OnInteractionDone() { + delete this; +} + +} // namespace safe_browsing
diff --git a/chrome/browser/safe_browsing/chrome_cleaner/chrome_cleaner_dialog_controller.h b/chrome/browser/safe_browsing/chrome_cleaner/chrome_cleaner_dialog_controller_win.h similarity index 87% rename from chrome/browser/safe_browsing/chrome_cleaner/chrome_cleaner_dialog_controller.h rename to chrome/browser/safe_browsing/chrome_cleaner/chrome_cleaner_dialog_controller_win.h index 60d359b..cda8280f 100644 --- a/chrome/browser/safe_browsing/chrome_cleaner/chrome_cleaner_dialog_controller.h +++ b/chrome/browser/safe_browsing/chrome_cleaner/chrome_cleaner_dialog_controller_win.h
@@ -2,8 +2,8 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#ifndef CHROME_BROWSER_SAFE_BROWSING_CHROME_CLEANER_CHROME_CLEANER_DIALOG_CONTROLLER_H_ -#define CHROME_BROWSER_SAFE_BROWSING_CHROME_CLEANER_CHROME_CLEANER_DIALOG_CONTROLLER_H_ +#ifndef CHROME_BROWSER_SAFE_BROWSING_CHROME_CLEANER_CHROME_CLEANER_DIALOG_CONTROLLER_WIN_H_ +#define CHROME_BROWSER_SAFE_BROWSING_CHROME_CLEANER_CHROME_CLEANER_DIALOG_CONTROLLER_WIN_H_ #include <vector> @@ -26,7 +26,7 @@ base::string16 GetWindowTitle() const; base::string16 GetMainText() const; base::string16 GetAcceptButtonLabel() const; - base::string16 GetAdvancedButtonLabel() const; + base::string16 GetDetailsButtonLabel() const; // Called by the Cleaner dialog when the dialog has been shown. Used for // reporting metrics. @@ -45,11 +45,11 @@ // eventually delete itself and no member functions should be called after // that. void Close(); - // Called when the advanced button is clicked, after which the dialog will - // close. After a call to |AdvancedButtonClicked()|, the controller will + // Called when the details button is clicked, after which the dialog will + // close. After a call to |DetailsButtonClicked()|, the controller will // eventually delete itself and no member functions should be called after // that. - void AdvancedButtonClicked(); + void DetailsButtonClicked(); protected: ~ChromeCleanerDialogController(); @@ -62,4 +62,4 @@ } // namespace safe_browsing -#endif // CHROME_BROWSER_SAFE_BROWSING_CHROME_CLEANER_CHROME_CLEANER_DIALOG_CONTROLLER_H_ +#endif // CHROME_BROWSER_SAFE_BROWSING_CHROME_CLEANER_CHROME_CLEANER_DIALOG_CONTROLLER_WIN_H_
diff --git a/chrome/browser/safe_browsing/chrome_cleaner/reporter_runner_browsertest_win.cc b/chrome/browser/safe_browsing/chrome_cleaner/reporter_runner_browsertest_win.cc index 36d420c..ec451294 100644 --- a/chrome/browser/safe_browsing/chrome_cleaner/reporter_runner_browsertest_win.cc +++ b/chrome/browser/safe_browsing/chrome_cleaner/reporter_runner_browsertest_win.cc
@@ -41,7 +41,7 @@ #include "components/chrome_cleaner/public/constants/constants.h" #include "components/component_updater/pref_names.h" #include "components/prefs/pref_service.h" -#include "components/safe_browsing_db/safe_browsing_prefs.h" +#include "components/safe_browsing/common/safe_browsing_prefs.h" #include "mojo/edk/embedder/embedder.h" #include "mojo/edk/embedder/incoming_broker_client_invitation.h" #include "mojo/edk/embedder/scoped_ipc_support.h" @@ -700,6 +700,11 @@ } IN_PROC_BROWSER_TEST_P(ReporterRunnerTest, RunDaily) { + // When the kInBrowserCleanerUIFeature feature is enabled, the reporter should + // never run daily. Test that case separately. + if (in_browser_cleaner_ui_) + return; + PrefService* local_state = g_browser_process->local_state(); local_state->SetBoolean(prefs::kSwReporterPendingPrompt, true); SetDaysSinceLastTriggered(kDaysBetweenSuccessfulSwReporterRuns - 1); @@ -728,6 +733,30 @@ ExpectToRunAgain(kDaysBetweenSuccessfulSwReporterRuns); } +IN_PROC_BROWSER_TEST_P(ReporterRunnerTest, InBrowserUINoRunDaily) { + // Ensure that the reporter always runs every + // kDaysBetweenSuccessfulSwReporterRuns days when kInBrowserCleanerUIFeature + // is enabled. The case when kInBrowserCleanerUIFeature is disabled is tested + // separately. + if (!in_browser_cleaner_ui_) + return; + + // Users can have the pending prompt set to true when migrating to the new UI, + // but it should be disregarded and the reporter should only be run every + // kDaysBetweenSuccessfulSwReporterRuns days. + PrefService* local_state = g_browser_process->local_state(); + local_state->SetBoolean(prefs::kSwReporterPendingPrompt, true); + SetDaysSinceLastTriggered(kDaysBetweenSuccessfulSwReporterRuns - 1); + ASSERT_GT(kDaysBetweenSuccessfulSwReporterRuns - 1, + kDaysBetweenSwReporterRunsForPendingPrompt); + RunReporter(chrome_cleaner::kSwReporterNothingFound); + + // Pending prompt is set, but we should not run the reporter since it hasn't + // been kDaysBetweenSuccessfulSwReporterRuns days since the last run. + ExpectReporterLaunches(0, 0, false); + ExpectToRunAgain(1); +} + IN_PROC_BROWSER_TEST_P(ReporterRunnerTest, ParameterChange) { // If the reporter is run several times with different parameters, it should // only be launched once, with the last parameter set.
diff --git a/chrome/browser/safe_browsing/chrome_cleaner/reporter_runner_win.cc b/chrome/browser/safe_browsing/chrome_cleaner/reporter_runner_win.cc index e3cb48c..fcf56b5 100644 --- a/chrome/browser/safe_browsing/chrome_cleaner/reporter_runner_win.cc +++ b/chrome/browser/safe_browsing/chrome_cleaner/reporter_runner_win.cc
@@ -973,11 +973,15 @@ // Run a queue of reporters if none have been triggered in the last // |days_between_reporter_runs_| days, which depends if there is a pending // prompt to be added to Chrome's menu. - if (local_state->GetBoolean(prefs::kSwReporterPendingPrompt)) { + // + // There is no concept of a pending prompt if the kInBrowserCleanerUIFeature + // feature is enabled, so always use kDaysBetweenSuccessfulSwReporterRuns in + // that case. + days_between_reporter_runs_ = kDaysBetweenSuccessfulSwReporterRuns; + if (!base::FeatureList::IsEnabled(kInBrowserCleanerUIFeature) && + local_state->GetBoolean(prefs::kSwReporterPendingPrompt)) { days_between_reporter_runs_ = kDaysBetweenSwReporterRunsForPendingPrompt; RecordReporterStepHistogram(SW_REPORTER_RAN_DAILY); - } else { - days_between_reporter_runs_ = kDaysBetweenSuccessfulSwReporterRuns; } const base::Time now = Now(); const base::Time last_time_triggered = base::Time::FromInternalValue(
diff --git a/chrome/browser/safe_browsing/chrome_cleaner/srt_client_info_win.cc b/chrome/browser/safe_browsing/chrome_cleaner/srt_client_info_win.cc index 1d72cfa..eb5975d 100644 --- a/chrome/browser/safe_browsing/chrome_cleaner/srt_client_info_win.cc +++ b/chrome/browser/safe_browsing/chrome_cleaner/srt_client_info_win.cc
@@ -9,7 +9,7 @@ #include "chrome/browser/profiles/profile.h" #include "chrome/browser/profiles/profile_manager.h" #include "chrome/common/channel_info.h" -#include "components/safe_browsing_db/safe_browsing_prefs.h" +#include "components/safe_browsing/common/safe_browsing_prefs.h" #include "components/version_info/version_info.h" namespace safe_browsing {
diff --git a/chrome/browser/safe_browsing/chrome_password_protection_service.cc b/chrome/browser/safe_browsing/chrome_password_protection_service.cc index 053284d..0a22684a 100644 --- a/chrome/browser/safe_browsing/chrome_password_protection_service.cc +++ b/chrome/browser/safe_browsing/chrome_password_protection_service.cc
@@ -14,9 +14,9 @@ #include "chrome/browser/safe_browsing/safe_browsing_service.h" #include "chrome/browser/sync/profile_sync_service_factory.h" #include "components/browser_sync/profile_sync_service.h" +#include "components/safe_browsing/common/safe_browsing_prefs.h" #include "components/safe_browsing/password_protection/password_protection_request.h" #include "components/safe_browsing_db/database_manager.h" -#include "components/safe_browsing_db/safe_browsing_prefs.h" using content::BrowserThread;
diff --git a/chrome/browser/safe_browsing/client_side_detection_host.cc b/chrome/browser/safe_browsing/client_side_detection_host.cc index b12aa7d..838bc9d 100644 --- a/chrome/browser/safe_browsing/client_side_detection_host.cc +++ b/chrome/browser/safe_browsing/client_side_detection_host.cc
@@ -21,10 +21,10 @@ #include "chrome/browser/safe_browsing/safe_browsing_service.h" #include "chrome/common/pref_names.h" #include "components/prefs/pref_service.h" +#include "components/safe_browsing/common/safe_browsing_prefs.h" #include "components/safe_browsing/common/safebrowsing_messages.h" #include "components/safe_browsing/csd.pb.h" #include "components/safe_browsing_db/database_manager.h" -#include "components/safe_browsing_db/safe_browsing_prefs.h" #include "content/public/browser/browser_thread.h" #include "content/public/browser/navigation_controller.h" #include "content/public/browser/navigation_entry.h"
diff --git a/chrome/browser/safe_browsing/client_side_detection_service.cc b/chrome/browser/safe_browsing/client_side_detection_service.cc index f2b691b..4fa5786 100644 --- a/chrome/browser/safe_browsing/client_side_detection_service.cc +++ b/chrome/browser/safe_browsing/client_side_detection_service.cc
@@ -23,9 +23,9 @@ #include "chrome/common/safe_browsing/client_model.pb.h" #include "components/data_use_measurement/core/data_use_user_data.h" #include "components/prefs/pref_service.h" +#include "components/safe_browsing/common/safe_browsing_prefs.h" #include "components/safe_browsing/common/safebrowsing_messages.h" #include "components/safe_browsing/csd.pb.h" -#include "components/safe_browsing_db/safe_browsing_prefs.h" #include "content/public/browser/browser_thread.h" #include "content/public/browser/notification_service.h" #include "content/public/browser/notification_types.h"
diff --git a/chrome/browser/safe_browsing/download_protection_service.cc b/chrome/browser/safe_browsing/download_protection_service.cc index 6681ae3e..7a886e3 100644 --- a/chrome/browser/safe_browsing/download_protection_service.cc +++ b/chrome/browser/safe_browsing/download_protection_service.cc
@@ -54,9 +54,9 @@ #include "components/google/core/browser/google_util.h" #include "components/history/core/browser/history_service.h" #include "components/prefs/pref_service.h" +#include "components/safe_browsing/common/safe_browsing_prefs.h" #include "components/safe_browsing/common/safebrowsing_switches.h" #include "components/safe_browsing/csd.pb.h" -#include "components/safe_browsing_db/safe_browsing_prefs.h" #include "content/public/browser/browser_thread.h" #include "content/public/browser/download_item.h" #include "content/public/browser/page_navigator.h" @@ -948,7 +948,7 @@ // Prepares URLs to be put into a ping message. Currently this just shortens // data: URIs, other URLs are included verbatim. If this is a sampled binary, - // we'll send a lite-ping which strips all PII. + // we'll send a light-ping which strips PII from the URL. std::string SanitizeUrl(const GURL& url) const { if (type_ == ClientDownloadRequest::SAMPLED_UNSUPPORTED_FILE) return url.GetOrigin().spec(); @@ -1022,14 +1022,8 @@ } request.set_user_initiated(item_->HasUserGesture()); - if (type_ == ClientDownloadRequest::SAMPLED_UNSUPPORTED_FILE) { - request.set_file_basename( - base::FilePath(item_->GetTargetFilePath().Extension()) - .AsUTF8Unsafe()); - } else { - request.set_file_basename( + request.set_file_basename( item_->GetTargetFilePath().BaseName().AsUTF8Unsafe()); - } request.set_download_type(type_); ReferrerChainData* referrer_chain_data =
diff --git a/chrome/browser/safe_browsing/download_protection_service_unittest.cc b/chrome/browser/safe_browsing/download_protection_service_unittest.cc index 94c4c68c..e8d6a59 100644 --- a/chrome/browser/safe_browsing/download_protection_service_unittest.cc +++ b/chrome/browser/safe_browsing/download_protection_service_unittest.cc
@@ -38,10 +38,10 @@ #include "chrome/test/base/testing_profile.h" #include "components/history/core/browser/history_service.h" #include "components/prefs/pref_service.h" +#include "components/safe_browsing/common/safe_browsing_prefs.h" #include "components/safe_browsing/common/safebrowsing_switches.h" #include "components/safe_browsing/csd.pb.h" #include "components/safe_browsing_db/database_manager.h" -#include "components/safe_browsing_db/safe_browsing_prefs.h" #include "components/safe_browsing_db/test_database_manager.h" #include "content/public/browser/download_danger_type.h" #include "content/public/browser/page_navigator.h" @@ -66,6 +66,7 @@ using ::testing::ElementsAre; using ::testing::Invoke; using ::testing::Mock; +using ::testing::NiceMock; using ::testing::NotNull; using ::testing::Return; using ::testing::ReturnRef; @@ -193,6 +194,8 @@ RunLoop run_loop_; }; +using NiceMockDownloadItem = NiceMock<content::MockDownloadItem>; + } // namespace ACTION_P(SetCertificateContents, contents) { @@ -406,7 +409,7 @@ } void PrepareBasicDownloadItem( - content::MockDownloadItem* item, + NiceMockDownloadItem* item, const std::vector<std::string> url_chain_items, const std::string& referrer_url, const base::FilePath::StringType& tmp_path_literal, @@ -419,7 +422,7 @@ } void PrepareBasicDownloadItemWithFullPaths( - content::MockDownloadItem* item, + NiceMockDownloadItem* item, const std::vector<std::string> url_chain_items, const std::string& referrer_url, const base::FilePath& tmp_full_path, @@ -427,17 +430,14 @@ url_chain_.clear(); for (std::string item: url_chain_items) url_chain_.push_back(GURL(item)); + if (url_chain_.empty()) + url_chain_.push_back(GURL()); referrer_ = GURL(referrer_url); tmp_path_ = tmp_full_path; final_path_ = final_full_path; hash_ = "hash"; - if (url_chain_.size() > 0) { - EXPECT_CALL(*item, GetURL()).WillRepeatedly(ReturnRef(url_chain_.back())); - } else{ - GURL empty_url; - EXPECT_CALL(*item, GetURL()).WillRepeatedly(ReturnRef(empty_url)); - } + EXPECT_CALL(*item, GetURL()).WillRepeatedly(ReturnRef(url_chain_.back())); EXPECT_CALL(*item, GetFullPath()).WillRepeatedly(ReturnRef(tmp_path_)); EXPECT_CALL(*item, GetTargetFilePath()) .WillRepeatedly(ReturnRef(final_path_)); @@ -551,7 +551,8 @@ base::ScopedTempDir profile_dir_; std::unique_ptr<TestingProfile> profile_; // The following 5 fields are used by PrepareBasicDownloadItem() function to - // store attributes of the last download item. + // store attributes of the last download item. They can be modified + // afterwards and the *item will return the new values. std::vector<GURL> url_chain_; GURL referrer_; base::FilePath tmp_path_; @@ -567,7 +568,7 @@ &factory, ClientDownloadResponse::SAFE, net::HTTP_OK, net::URLRequestStatus::SUCCESS); - content::MockDownloadItem item; + NiceMockDownloadItem item; if (type == ZIP) { PrepareBasicDownloadItem(&item, {"http://www.evil.com/a.zip"}, // url_chain "http://www.google.com/", // referrer @@ -605,7 +606,7 @@ } TEST_F(DownloadProtectionServiceTest, CheckClientDownloadInvalidUrl) { - content::MockDownloadItem item; + NiceMockDownloadItem item; { PrepareBasicDownloadItem(&item, std::vector<std::string>(), // empty url_chain @@ -638,7 +639,7 @@ } TEST_F(DownloadProtectionServiceTest, CheckClientDownloadNotABinary) { - content::MockDownloadItem item; + NiceMockDownloadItem item; PrepareBasicDownloadItem( &item, std::vector<std::string>(), // empty url_chain @@ -662,7 +663,7 @@ &factory, ClientDownloadResponse::DANGEROUS, net::HTTP_OK, net::URLRequestStatus::SUCCESS); - content::MockDownloadItem item; + NiceMockDownloadItem item; PrepareBasicDownloadItem( &item, std::vector<std::string>(), // empty url_chain @@ -758,7 +759,7 @@ &factory, ClientDownloadResponse::SAFE, net::HTTP_OK, net::URLRequestStatus::SUCCESS); - content::MockDownloadItem item; + NiceMockDownloadItem item; PrepareBasicDownloadItem( &item, std::vector<std::string>(), // empty url_chain @@ -908,20 +909,21 @@ &factory, ClientDownloadResponse::DANGEROUS, net::HTTP_OK, net::URLRequestStatus::SUCCESS); - content::MockDownloadItem item; + NiceMockDownloadItem item; PrepareBasicDownloadItem( - &item, - std::vector<std::string>(), // empty url_chain - "http://www.google.com/", // referrer - FILE_PATH_LITERAL("a.tmp"), // tmp_path - FILE_PATH_LITERAL("a.foobar_unknown_ype")); // final_path + &item, + // Add paths so we can check they are properly removed. + {"http://referrer.com/1/2", "http://referrer.com/3/4", + "http://download.com/path/a.foobar_unknown_type"}, + "http://referrer.com/3/4", // Referrer + FILE_PATH_LITERAL("a.tmp"), // tmp_path + FILE_PATH_LITERAL("a.foobar_unknown_type")); // final_path EXPECT_CALL(*binary_feature_extractor_.get(), CheckSignature(tmp_path_, _)) .Times(1); EXPECT_CALL(*binary_feature_extractor_.get(), ExtractImageFeatures( tmp_path_, BinaryFeatureExtractor::kDefaultOptions, _, _)) .Times(1); - url_chain_.push_back(GURL("http://www.whitelist.com/a.foobar_unknown_type")); // Set ping sample rate to 1.00 so download_service_ will always send a // "light" ping for unknown types if allowed. @@ -953,8 +955,8 @@ run_loop.Run(); EXPECT_TRUE(IsResult(DownloadProtectionService::UNKNOWN)); ASSERT_TRUE(HasClientDownloadRequest()); - // Verify it's a "light" ping, check that URLs don't have paths, and - // and verify filename is just an extension. + + // Verify it's a "light" ping, check that URLs don't have paths. auto* req = GetClientDownloadRequest(); EXPECT_EQ(ClientDownloadRequest::SAMPLED_UNSUPPORTED_FILE, req->download_type()); @@ -964,7 +966,6 @@ EXPECT_EQ(GURL(resource.referrer()).GetOrigin().spec(), resource.referrer()); } - EXPECT_EQ('.', req->file_basename()[0]); ClearClientDownloadRequest(); } { @@ -1003,7 +1004,7 @@ &factory, ClientDownloadResponse::SAFE, net::HTTP_INTERNAL_SERVER_ERROR, net::URLRequestStatus::FAILED); - content::MockDownloadItem item; + NiceMockDownloadItem item; PrepareBasicDownloadItem( &item, {"http://www.evil.com/a.exe"}, // url_chain @@ -1032,7 +1033,7 @@ PrepareResponse(&factory, ClientDownloadResponse::SAFE, net::HTTP_OK, net::URLRequestStatus::SUCCESS); - content::MockDownloadItem item; + NiceMockDownloadItem item; PrepareBasicDownloadItem(&item, {"http://www.evil.com/a.exe"}, // url_chain "http://www.google.com/", // referrer FILE_PATH_LITERAL("a.tmp"), // tmp_path @@ -1190,7 +1191,7 @@ &factory, ClientDownloadResponse::DANGEROUS, net::HTTP_OK, net::URLRequestStatus::SUCCESS); - content::MockDownloadItem item; + NiceMockDownloadItem item; PrepareBasicDownloadItem(&item, {"http://www.evil.com/a.exe"}, // url_chain "http://www.google.com/", // referrer @@ -1223,7 +1224,7 @@ &factory, ClientDownloadResponse::DANGEROUS, net::HTTP_OK, net::URLRequestStatus::SUCCESS); - content::MockDownloadItem item; + NiceMockDownloadItem item; PrepareBasicDownloadItem( &item, {"blob:http://www.evil.com/50b85f60-71e4-11e4-82f8-0800200c9a66"}, @@ -1257,7 +1258,7 @@ &factory, ClientDownloadResponse::DANGEROUS, net::HTTP_OK, net::URLRequestStatus::SUCCESS); - content::MockDownloadItem item; + NiceMockDownloadItem item; PrepareBasicDownloadItem( &item, {"data:text/html:base64,", "data:text/html:base64,blahblahblah", @@ -1315,7 +1316,7 @@ &factory, ClientDownloadResponse::SAFE, net::HTTP_OK, net::URLRequestStatus::SUCCESS); - content::MockDownloadItem item; + NiceMockDownloadItem item; PrepareBasicDownloadItem( &item, {"http://www.evil.com/a.zip"}, // url_chain @@ -1447,7 +1448,7 @@ TEST_F(DownloadProtectionServiceTest, CheckClientDownloadValidateRequest) { net::TestURLFetcherFactory factory; - content::MockDownloadItem item; + NiceMockDownloadItem item; PrepareBasicDownloadItem( &item, {"http://www.google.com/", @@ -1521,7 +1522,7 @@ CheckClientDownloadValidateRequestNoSignature) { net::TestURLFetcherFactory factory; - content::MockDownloadItem item; + NiceMockDownloadItem item; PrepareBasicDownloadItem( &item, {"http://www.google.com/", @@ -1581,7 +1582,7 @@ CheckClientDownloadValidateRequestTabHistory) { net::TestURLFetcherFactory factory; - content::MockDownloadItem item; + NiceMockDownloadItem item; PrepareBasicDownloadItem( &item, {"http://www.google.com/", @@ -1746,7 +1747,7 @@ GURL referrer("http://www.google.com/"); std::string hash = "hash"; - content::MockDownloadItem item; + NiceMockDownloadItem item; EXPECT_CALL(item, GetURL()).WillRepeatedly(ReturnRef(url_chain.back())); EXPECT_CALL(item, GetUrlChain()).WillRepeatedly(ReturnRef(url_chain)); EXPECT_CALL(item, GetReferrerUrl()).WillRepeatedly(ReturnRef(referrer)); @@ -1810,7 +1811,7 @@ TEST_F(DownloadProtectionServiceTest, TestDownloadRequestTimeout) { net::TestURLFetcherFactory factory; - content::MockDownloadItem item; + NiceMockDownloadItem item; PrepareBasicDownloadItem( &item, {"http://www.evil.com/bla.exe"}, // url_chain @@ -1843,7 +1844,7 @@ TEST_F(DownloadProtectionServiceTest, TestDownloadItemDestroyed) { { - content::MockDownloadItem item; + NiceMockDownloadItem item; PrepareBasicDownloadItem( &item, {"http://www.evil.com/bla.exe"}, // url_chain @@ -1875,8 +1876,7 @@ TEST_F(DownloadProtectionServiceTest, TestDownloadItemDestroyedDuringWhitelistCheck) { net::TestURLFetcherFactory factory; - std::unique_ptr<content::MockDownloadItem> item( - new content::MockDownloadItem); + std::unique_ptr<NiceMockDownloadItem> item(new NiceMockDownloadItem); PrepareBasicDownloadItem( item.get(), {"http://www.evil.com/bla.exe"}, // url_chain @@ -2030,7 +2030,7 @@ } TEST_F(DownloadProtectionServiceTest, GetAndSetDownloadPingToken) { - content::MockDownloadItem item; + NiceMockDownloadItem item; EXPECT_TRUE(DownloadProtectionService::GetDownloadPingToken(&item).empty()); std::string token = "download_ping_token"; DownloadProtectionService::SetDownloadPingToken(&item, token); @@ -2296,7 +2296,7 @@ }; TEST_F(DownloadProtectionServiceFlagTest, CheckClientDownloadOverridenByFlag) { - content::MockDownloadItem item; + NiceMockDownloadItem item; PrepareBasicDownloadItem( &item, {"http://www.evil.com/a.exe"}, // url_chain @@ -2327,7 +2327,7 @@ // blacklisted by hash. TEST_F(DownloadProtectionServiceFlagTest, CheckClientDownloadZipOverridenByFlag) { - content::MockDownloadItem item; + NiceMockDownloadItem item; PrepareBasicDownloadItemWithFullPaths( &item, {"http://www.evil.com/a.exe"}, // url_chain
diff --git a/chrome/browser/safe_browsing/incident_reporting/extension_data_collection_unittest.cc b/chrome/browser/safe_browsing/incident_reporting/extension_data_collection_unittest.cc index 4d9e89d8..8378b6c 100644 --- a/chrome/browser/safe_browsing/incident_reporting/extension_data_collection_unittest.cc +++ b/chrome/browser/safe_browsing/incident_reporting/extension_data_collection_unittest.cc
@@ -20,8 +20,8 @@ #include "chrome/test/base/testing_browser_process.h" #include "chrome/test/base/testing_profile.h" #include "chrome/test/base/testing_profile_manager.h" +#include "components/safe_browsing/common/safe_browsing_prefs.h" #include "components/safe_browsing/csd.pb.h" -#include "components/safe_browsing_db/safe_browsing_prefs.h" #include "components/sync_preferences/testing_pref_service_syncable.h" #include "content/public/test/test_browser_thread_bundle.h" #include "content/public/test/test_utils.h"
diff --git a/chrome/browser/safe_browsing/incident_reporting/incident_reporting_service.cc b/chrome/browser/safe_browsing/incident_reporting/incident_reporting_service.cc index 72329940..0275fdd 100644 --- a/chrome/browser/safe_browsing/incident_reporting/incident_reporting_service.cc +++ b/chrome/browser/safe_browsing/incident_reporting/incident_reporting_service.cc
@@ -35,9 +35,9 @@ #include "chrome/common/chrome_features.h" #include "chrome/common/pref_names.h" #include "components/prefs/pref_service.h" +#include "components/safe_browsing/common/safe_browsing_prefs.h" #include "components/safe_browsing/csd.pb.h" #include "components/safe_browsing_db/database_manager.h" -#include "components/safe_browsing_db/safe_browsing_prefs.h" #include "content/public/browser/browser_thread.h" #include "content/public/browser/notification_service.h" #include "net/url_request/url_request_context_getter.h"
diff --git a/chrome/browser/safe_browsing/incident_reporting/incident_reporting_service_unittest.cc b/chrome/browser/safe_browsing/incident_reporting/incident_reporting_service_unittest.cc index 63b50d8..9d4d540 100644 --- a/chrome/browser/safe_browsing/incident_reporting/incident_reporting_service_unittest.cc +++ b/chrome/browser/safe_browsing/incident_reporting/incident_reporting_service_unittest.cc
@@ -34,8 +34,8 @@ #include "chrome/test/base/testing_browser_process.h" #include "chrome/test/base/testing_profile.h" #include "chrome/test/base/testing_profile_manager.h" +#include "components/safe_browsing/common/safe_browsing_prefs.h" #include "components/safe_browsing/csd.pb.h" -#include "components/safe_browsing_db/safe_browsing_prefs.h" #include "components/sync_preferences/testing_pref_service_syncable.h" #include "content/public/test/test_browser_thread_bundle.h" #include "extensions/browser/quota_service.h"
diff --git a/chrome/browser/safe_browsing/incident_reporting/last_download_finder_unittest.cc b/chrome/browser/safe_browsing/incident_reporting/last_download_finder_unittest.cc index 033d23c8..d3cf2fd1e 100644 --- a/chrome/browser/safe_browsing/incident_reporting/last_download_finder_unittest.cc +++ b/chrome/browser/safe_browsing/incident_reporting/last_download_finder_unittest.cc
@@ -43,8 +43,8 @@ #include "components/history/core/browser/history_constants.h" #include "components/history/core/browser/history_database_params.h" #include "components/history/core/browser/history_service.h" +#include "components/safe_browsing/common/safe_browsing_prefs.h" #include "components/safe_browsing/csd.pb.h" -#include "components/safe_browsing_db/safe_browsing_prefs.h" #include "components/sync_preferences/testing_pref_service_syncable.h" #include "content/public/test/test_browser_thread_bundle.h" #include "content/public/test/test_utils.h"
diff --git a/chrome/browser/safe_browsing/local_database_manager.cc b/chrome/browser/safe_browsing/local_database_manager.cc index 33c0044..7c031ea 100644 --- a/chrome/browser/safe_browsing/local_database_manager.cc +++ b/chrome/browser/safe_browsing/local_database_manager.cc
@@ -33,8 +33,8 @@ #include "chrome/common/chrome_switches.h" #include "chrome/common/pref_names.h" #include "components/prefs/pref_service.h" +#include "components/safe_browsing/common/safe_browsing_prefs.h" #include "components/safe_browsing/common/safebrowsing_switches.h" -#include "components/safe_browsing_db/safe_browsing_prefs.h" #include "components/safe_browsing_db/util.h" #include "components/safe_browsing_db/v4_protocol_manager_util.h" #include "content/public/browser/browser_thread.h"
diff --git a/chrome/browser/safe_browsing/local_database_manager.h b/chrome/browser/safe_browsing/local_database_manager.h index ea55fbd..185aa470 100644 --- a/chrome/browser/safe_browsing/local_database_manager.h +++ b/chrome/browser/safe_browsing/local_database_manager.h
@@ -27,8 +27,8 @@ #include "base/time/time.h" #include "chrome/browser/safe_browsing/protocol_manager.h" #include "chrome/browser/safe_browsing/safe_browsing_util.h" +#include "components/safe_browsing/common/safe_browsing_prefs.h" #include "components/safe_browsing_db/database_manager.h" -#include "components/safe_browsing_db/safe_browsing_prefs.h" #include "components/safe_browsing_db/safebrowsing.pb.h" #include "components/safe_browsing_db/util.h" #include "url/gurl.h"
diff --git a/chrome/browser/safe_browsing/notification_image_reporter.cc b/chrome/browser/safe_browsing/notification_image_reporter.cc index 00f7a12..5f859e8b 100644 --- a/chrome/browser/safe_browsing/notification_image_reporter.cc +++ b/chrome/browser/safe_browsing/notification_image_reporter.cc
@@ -18,9 +18,9 @@ #include "chrome/browser/browser_process.h" #include "chrome/browser/profiles/profile.h" #include "chrome/browser/safe_browsing/safe_browsing_service.h" +#include "components/safe_browsing/common/safe_browsing_prefs.h" #include "components/safe_browsing/csd.pb.h" #include "components/safe_browsing_db/database_manager.h" -#include "components/safe_browsing_db/safe_browsing_prefs.h" #include "components/variations/variations_associated_data.h" #include "content/public/browser/browser_thread.h" #include "net/base/net_errors.h"
diff --git a/chrome/browser/safe_browsing/notification_image_reporter_unittest.cc b/chrome/browser/safe_browsing/notification_image_reporter_unittest.cc index 780ff24..031d0b45 100644 --- a/chrome/browser/safe_browsing/notification_image_reporter_unittest.cc +++ b/chrome/browser/safe_browsing/notification_image_reporter_unittest.cc
@@ -13,8 +13,8 @@ #include "chrome/browser/safe_browsing/test_safe_browsing_service.h" #include "chrome/test/base/testing_browser_process.h" #include "chrome/test/base/testing_profile.h" +#include "components/safe_browsing/common/safe_browsing_prefs.h" #include "components/safe_browsing/csd.pb.h" -#include "components/safe_browsing_db/safe_browsing_prefs.h" #include "components/safe_browsing_db/test_database_manager.h" #include "content/public/browser/browser_thread.h" #include "content/public/test/test_browser_thread_bundle.h"
diff --git a/chrome/browser/safe_browsing/protocol_manager.h b/chrome/browser/safe_browsing/protocol_manager.h index ae17540..8878df62 100644 --- a/chrome/browser/safe_browsing/protocol_manager.h +++ b/chrome/browser/safe_browsing/protocol_manager.h
@@ -30,7 +30,7 @@ #include "chrome/browser/safe_browsing/chunk_range.h" #include "chrome/browser/safe_browsing/protocol_parser.h" #include "chrome/browser/safe_browsing/safe_browsing_util.h" -#include "components/safe_browsing_db/safe_browsing_prefs.h" +#include "components/safe_browsing/common/safe_browsing_prefs.h" #include "components/safe_browsing_db/safebrowsing.pb.h" #include "components/safe_browsing_db/util.h" #include "net/url_request/url_fetcher_delegate.h"
diff --git a/chrome/browser/safe_browsing/protocol_manager_unittest.cc b/chrome/browser/safe_browsing/protocol_manager_unittest.cc index 8e47595..51502cbfd 100644 --- a/chrome/browser/safe_browsing/protocol_manager_unittest.cc +++ b/chrome/browser/safe_browsing/protocol_manager_unittest.cc
@@ -13,7 +13,7 @@ #include "base/threading/thread_task_runner_handle.h" #include "base/time/time.h" #include "chrome/browser/safe_browsing/chunk.pb.h" -#include "components/safe_browsing_db/safe_browsing_prefs.h" +#include "components/safe_browsing/common/safe_browsing_prefs.h" #include "components/safe_browsing_db/safebrowsing.pb.h" #include "components/safe_browsing_db/util.h" #include "content/public/test/test_browser_thread_bundle.h"
diff --git a/chrome/browser/safe_browsing/safe_browsing_blocking_page.cc b/chrome/browser/safe_browsing/safe_browsing_blocking_page.cc index e866451..f979d96 100644 --- a/chrome/browser/safe_browsing/safe_browsing_blocking_page.cc +++ b/chrome/browser/safe_browsing/safe_browsing_blocking_page.cc
@@ -17,8 +17,8 @@ #include "chrome/common/pref_names.h" #include "components/prefs/pref_service.h" #include "components/safe_browsing/browser/threat_details.h" +#include "components/safe_browsing/common/safe_browsing_prefs.h" #include "components/safe_browsing/triggers/trigger_manager.h" -#include "components/safe_browsing_db/safe_browsing_prefs.h" #include "content/public/browser/browser_thread.h" #include "content/public/browser/interstitial_page.h" #include "content/public/browser/navigation_entry.h"
diff --git a/chrome/browser/safe_browsing/safe_browsing_blocking_page_test.cc b/chrome/browser/safe_browsing/safe_browsing_blocking_page_test.cc index 42800c98..cfbc904 100644 --- a/chrome/browser/safe_browsing/safe_browsing_blocking_page_test.cc +++ b/chrome/browser/safe_browsing/safe_browsing_blocking_page_test.cc
@@ -37,8 +37,8 @@ #include "chrome/test/base/ui_test_utils.h" #include "components/prefs/pref_service.h" #include "components/safe_browsing/browser/threat_details.h" +#include "components/safe_browsing/common/safe_browsing_prefs.h" #include "components/safe_browsing_db/database_manager.h" -#include "components/safe_browsing_db/safe_browsing_prefs.h" #include "components/safe_browsing_db/test_database_manager.h" #include "components/safe_browsing_db/util.h" #include "components/security_interstitials/core/controller_client.h"
diff --git a/chrome/browser/safe_browsing/safe_browsing_blocking_page_unittest.cc b/chrome/browser/safe_browsing/safe_browsing_blocking_page_unittest.cc index 5690dac0..3c988fb 100644 --- a/chrome/browser/safe_browsing/safe_browsing_blocking_page_unittest.cc +++ b/chrome/browser/safe_browsing/safe_browsing_blocking_page_unittest.cc
@@ -16,7 +16,7 @@ #include "chrome/test/base/testing_profile.h" #include "components/prefs/pref_service.h" #include "components/safe_browsing/browser/threat_details.h" -#include "components/safe_browsing_db/safe_browsing_prefs.h" +#include "components/safe_browsing/common/safe_browsing_prefs.h" #include "content/public/browser/interstitial_page.h" #include "content/public/browser/navigation_entry.h" #include "content/public/browser/render_process_host.h"
diff --git a/chrome/browser/safe_browsing/safe_browsing_service.h b/chrome/browser/safe_browsing/safe_browsing_service.h index c207f65e3..c98e36b 100644 --- a/chrome/browser/safe_browsing/safe_browsing_service.h +++ b/chrome/browser/safe_browsing/safe_browsing_service.h
@@ -20,7 +20,7 @@ #include "base/observer_list.h" #include "base/sequenced_task_runner_helpers.h" #include "chrome/browser/safe_browsing/services_delegate.h" -#include "components/safe_browsing_db/safe_browsing_prefs.h" +#include "components/safe_browsing/common/safe_browsing_prefs.h" #include "components/safe_browsing_db/util.h" #include "components/safe_browsing_db/v4_feature_list.h" #include "content/public/browser/browser_thread.h"
diff --git a/chrome/browser/safe_browsing/ui_manager.cc b/chrome/browser/safe_browsing/ui_manager.cc index d3de4ec9..6cde6d90 100644 --- a/chrome/browser/safe_browsing/ui_manager.cc +++ b/chrome/browser/safe_browsing/ui_manager.cc
@@ -22,7 +22,7 @@ #include "chrome/common/url_constants.h" #include "components/prefs/pref_service.h" #include "components/safe_browsing/browser/threat_details.h" -#include "components/safe_browsing_db/safe_browsing_prefs.h" +#include "components/safe_browsing/common/safe_browsing_prefs.h" #include "content/public/browser/browser_thread.h" #include "content/public/browser/navigation_entry.h" #include "content/public/browser/notification_service.h"
diff --git a/chrome/browser/safe_browsing/ui_manager_unittest.cc b/chrome/browser/safe_browsing/ui_manager_unittest.cc index 174936a1..b0553ab 100644 --- a/chrome/browser/safe_browsing/ui_manager_unittest.cc +++ b/chrome/browser/safe_browsing/ui_manager_unittest.cc
@@ -10,7 +10,7 @@ #include "chrome/browser/safe_browsing/ui_manager.h" #include "chrome/test/base/chrome_render_view_host_test_harness.h" #include "chrome/test/base/testing_profile.h" -#include "components/safe_browsing_db/safe_browsing_prefs.h" +#include "components/safe_browsing/common/safe_browsing_prefs.h" #include "components/safe_browsing_db/util.h" #include "components/security_interstitials/core/base_safe_browsing_error_ui.h" #include "content/public/browser/navigation_entry.h"
diff --git a/chrome/browser/ssl/bad_clock_blocking_page.cc b/chrome/browser/ssl/bad_clock_blocking_page.cc index 02a5019..9a972b0 100644 --- a/chrome/browser/ssl/bad_clock_blocking_page.cc +++ b/chrome/browser/ssl/bad_clock_blocking_page.cc
@@ -15,7 +15,7 @@ #include "chrome/browser/renderer_preferences_util.h" #include "chrome/browser/ssl/cert_report_helper.h" #include "chrome/browser/ssl/ssl_cert_reporter.h" -#include "components/safe_browsing_db/safe_browsing_prefs.h" +#include "components/safe_browsing/common/safe_browsing_prefs.h" #include "components/security_interstitials/core/bad_clock_ui.h" #include "components/security_interstitials/core/metrics_helper.h" #include "content/public/browser/interstitial_page.h"
diff --git a/chrome/browser/ssl/captive_portal_blocking_page.cc b/chrome/browser/ssl/captive_portal_blocking_page.cc index dab9355..066233a3 100644 --- a/chrome/browser/ssl/captive_portal_blocking_page.cc +++ b/chrome/browser/ssl/captive_portal_blocking_page.cc
@@ -23,7 +23,7 @@ #include "chrome/grit/generated_resources.h" #include "components/captive_portal/captive_portal_detector.h" #include "components/certificate_reporting/error_reporter.h" -#include "components/safe_browsing_db/safe_browsing_prefs.h" +#include "components/safe_browsing/common/safe_browsing_prefs.h" #include "components/security_interstitials/core/controller_client.h" #include "components/security_interstitials/core/metrics_helper.h" #include "components/url_formatter/url_formatter.h"
diff --git a/chrome/browser/ssl/cert_report_helper.cc b/chrome/browser/ssl/cert_report_helper.cc index 315220d2..053ce92 100644 --- a/chrome/browser/ssl/cert_report_helper.cc +++ b/chrome/browser/ssl/cert_report_helper.cc
@@ -18,7 +18,7 @@ #include "chrome/browser/ssl/ssl_cert_reporter.h" #include "chrome/common/pref_names.h" #include "components/prefs/pref_service.h" -#include "components/safe_browsing_db/safe_browsing_prefs.h" +#include "components/safe_browsing/common/safe_browsing_prefs.h" #include "components/security_interstitials/core/controller_client.h" #include "components/security_interstitials/core/metrics_helper.h" #include "components/strings/grit/components_strings.h"
diff --git a/chrome/browser/ssl/certificate_reporting_test_utils.cc b/chrome/browser/ssl/certificate_reporting_test_utils.cc index 4fbb7e20..ba04b2bfa6 100644 --- a/chrome/browser/ssl/certificate_reporting_test_utils.cc +++ b/chrome/browser/ssl/certificate_reporting_test_utils.cc
@@ -17,7 +17,7 @@ #include "chrome/browser/ui/browser.h" #include "components/certificate_reporting/error_report.h" #include "components/prefs/pref_service.h" -#include "components/safe_browsing_db/safe_browsing_prefs.h" +#include "components/safe_browsing/common/safe_browsing_prefs.h" #include "components/variations/variations_associated_data.h" #include "net/url_request/report_sender.h" #include "net/url_request/url_request_context.h"
diff --git a/chrome/browser/ssl/ssl_blocking_page.cc b/chrome/browser/ssl/ssl_blocking_page.cc index 8d88825..27a004b7 100644 --- a/chrome/browser/ssl/ssl_blocking_page.cc +++ b/chrome/browser/ssl/ssl_blocking_page.cc
@@ -23,7 +23,7 @@ #include "chrome/common/chrome_switches.h" #include "chrome/common/pref_names.h" #include "components/prefs/pref_service.h" -#include "components/safe_browsing_db/safe_browsing_prefs.h" +#include "components/safe_browsing/common/safe_browsing_prefs.h" #include "components/security_interstitials/core/controller_client.h" #include "components/security_interstitials/core/metrics_helper.h" #include "components/security_interstitials/core/ssl_error_ui.h"
diff --git a/chrome/browser/ui/BUILD.gn b/chrome/browser/ui/BUILD.gn index b608ee7..e90d3dc6 100644 --- a/chrome/browser/ui/BUILD.gn +++ b/chrome/browser/ui/BUILD.gn
@@ -548,7 +548,7 @@ "//components/rappor", "//components/renderer_context_menu", "//components/resources", - "//components/safe_browsing_db:safe_browsing_prefs", + "//components/safe_browsing/common:safe_browsing_prefs", "//components/safe_json", "//components/search", "//components/search_engines", @@ -3087,8 +3087,8 @@ "input_method/input_method_engine_base.h", "network_profile_bubble.cc", "network_profile_bubble.h", - "views/chrome_cleaner_dialog.cc", - "views/chrome_cleaner_dialog.h", + "views/chrome_cleaner_dialog_win.cc", + "views/chrome_cleaner_dialog_win.h", "views/color_chooser_dialog.cc", "views/color_chooser_dialog.h", "views/critical_notification_bubble_view.cc",
diff --git a/chrome/browser/ui/cocoa/app_menu/app_menu_controller.h b/chrome/browser/ui/cocoa/app_menu/app_menu_controller.h index b3508a63..5718e87c 100644 --- a/chrome/browser/ui/cocoa/app_menu/app_menu_controller.h +++ b/chrome/browser/ui/cocoa/app_menu/app_menu_controller.h
@@ -9,6 +9,7 @@ #include <memory> +#include "base/mac/objc_property_releaser.h" #import "base/mac/scoped_nsobject.h" #include "base/time/time.h" #import "chrome/browser/ui/cocoa/has_weak_browser_pointer.h" @@ -131,6 +132,8 @@ MenuTrackedRootView* toolbarActionsOverflowItem_; BrowserActionsContainerView* overflowActionsContainerView_; + + base::mac::ObjCPropertyReleaser propertyReleaser_; } @property(retain, nonatomic) IBOutlet MenuTrackedRootView* editItem;
diff --git a/chrome/browser/ui/cocoa/app_menu/app_menu_controller.mm b/chrome/browser/ui/cocoa/app_menu/app_menu_controller.mm index 6670567..c333a96 100644 --- a/chrome/browser/ui/cocoa/app_menu/app_menu_controller.mm +++ b/chrome/browser/ui/cocoa/app_menu/app_menu_controller.mm
@@ -8,7 +8,6 @@ #include "base/bind.h" #include "base/mac/bundle_locations.h" -#include "base/mac/objc_release_properties.h" #include "base/macros.h" #include "base/memory/weak_ptr.h" #include "base/metrics/histogram_macros.h" @@ -602,6 +601,7 @@ - (id)initWithController:(AppMenuController*)controller { if ((self = [super initWithNibName:@"AppMenu" bundle:base::mac::FrameworkBundle()])) { + propertyReleaser_.Init(self, [AppMenuButtonViewController class]); controller_ = controller; [[NSNotificationCenter defaultCenter] addObserver:self @@ -614,7 +614,6 @@ - (void)dealloc { [[NSNotificationCenter defaultCenter] removeObserver:self]; - base::mac::ReleaseProperties(self); [super dealloc]; }
diff --git a/chrome/browser/ui/cocoa/find_bar/find_bar_cocoa_controller.mm b/chrome/browser/ui/cocoa/find_bar/find_bar_cocoa_controller.mm index c04cf5d..5195ecc 100644 --- a/chrome/browser/ui/cocoa/find_bar/find_bar_cocoa_controller.mm +++ b/chrome/browser/ui/cocoa/find_bar/find_bar_cocoa_controller.mm
@@ -303,6 +303,8 @@ // the list above. content::RenderViewHost* render_view_host = web_contents->GetRenderViewHost(); + + // TODO(tdresser): get the hardware timestamp from the NSEvent. render_view_host->GetWidget()->ForwardKeyboardEvent( NativeWebKeyboardEvent(event)); return YES;
diff --git a/chrome/browser/ui/cocoa/omnibox/omnibox_popup_cell.h b/chrome/browser/ui/cocoa/omnibox/omnibox_popup_cell.h index 4721370..21ba308 100644 --- a/chrome/browser/ui/cocoa/omnibox/omnibox_popup_cell.h +++ b/chrome/browser/ui/cocoa/omnibox/omnibox_popup_cell.h
@@ -68,8 +68,8 @@ + (CGFloat)getContentAreaWidth:(NSRect)cellFrame; -@end ++ (CGFloat)getContentTextHeight; -const CGFloat kContentLineHeight = 25.0; +@end #endif // CHROME_BROWSER_UI_COCOA_OMNIBOX_OMNIBOX_POPUP_CELL_H_
diff --git a/chrome/browser/ui/cocoa/omnibox/omnibox_popup_cell.mm b/chrome/browser/ui/cocoa/omnibox/omnibox_popup_cell.mm index e4067979..a41858a 100644 --- a/chrome/browser/ui/cocoa/omnibox/omnibox_popup_cell.mm +++ b/chrome/browser/ui/cocoa/omnibox/omnibox_popup_cell.mm
@@ -11,8 +11,9 @@ #include "base/i18n/rtl.h" #include "base/mac/foundation_util.h" -#include "base/mac/objc_release_properties.h" +#include "base/mac/objc_property_releaser.h" #include "base/mac/scoped_nsobject.h" +#include "base/metrics/field_trial_params.h" #include "base/strings/string_number_conversions.h" #include "base/strings/string_util.h" #include "base/strings/sys_string_conversions.h" @@ -21,6 +22,7 @@ #include "chrome/browser/ui/cocoa/omnibox/omnibox_view_mac.h" #import "chrome/browser/ui/cocoa/themed_window.h" #include "chrome/grit/generated_resources.h" +#include "components/omnibox/browser/omnibox_field_trial.h" #include "components/omnibox/browser/omnibox_popup_model.h" #include "components/omnibox/browser/suggestion_answer.h" #include "skia/ext/skia_utils_mac.h" @@ -31,14 +33,21 @@ namespace { -// How far to offset text. -const CGFloat kVerticalTextPadding = 3.0; +// Extra padding beyond the vertical text padding. +constexpr CGFloat kMaterialExtraVerticalImagePadding = 2.0; -const CGFloat kMaterialVerticalImagePadding = 5.0; +constexpr CGFloat kMaterialTextStartOffset = 27.0; -const CGFloat kMaterialTextStartOffset = 27.0; +constexpr CGFloat kMaterialImageXOffset = 6.0; -const CGFloat kMaterialImageXOffset = 6.0; +// Returns the margin that should appear at the top and bottom of the result. +CGFloat GetVerticalMargin() { + constexpr CGFloat kDefaultVerticalMargin = 3.0; + + return base::GetFieldTrialParamByFeatureAsInt( + omnibox::kUIExperimentVerticalMargin, + OmniboxFieldTrial::kUIVerticalMarginParam, kDefaultVerticalMargin); +} // Flips the given |rect| in context of the given |frame|. NSRect FlipIfRTL(NSRect rect, NSRect frame) { @@ -343,6 +352,11 @@ } // namespace +@interface OmniboxPopupCellData () { + base::mac::ObjCPropertyReleaser propertyReleaser_OmniboxPopupCellData_; +} +@end + @interface OmniboxPopupCell () - (CGFloat)drawMatchPart:(NSAttributedString*)attributedString withFrame:(NSRect)cellFrame @@ -413,15 +427,12 @@ } maxLines_ = 1; } + propertyReleaser_OmniboxPopupCellData_.Init(self, + [OmniboxPopupCellData class]); } return self; } -- (void)dealloc { - base::mac::ReleaseProperties(self); - [super dealloc]; -} - - (instancetype)copyWithZone:(NSZone*)zone { return [self retain]; } @@ -478,7 +489,8 @@ isDarkTheme ? [cellData incognitoImage] : [cellData image]; imageRect.size = [theImage size]; imageRect.origin.x += kMaterialImageXOffset + [tableView contentLeftPadding]; - imageRect.origin.y += kMaterialVerticalImagePadding; + imageRect.origin.y += + GetVerticalMargin() + kMaterialExtraVerticalImagePadding; [theImage drawInRect:FlipIfRTL(imageRect, cellFrame) fromRect:NSZeroRect operation:NSCompositeSourceOver @@ -488,7 +500,7 @@ NSPoint origin = NSMakePoint(kMaterialTextStartOffset + [tableView contentLeftPadding], - kVerticalTextPadding); + GetVerticalMargin()); if ([cellData matchType] == AutocompleteMatchType::SEARCH_SUGGEST_TAIL) { // Tail suggestions are rendered with a prefix (usually ellipsis), which // appear vertically stacked. @@ -505,9 +517,9 @@ if (descriptionMaxWidth > 0) { if ([cellData isAnswer]) { - origin = - NSMakePoint(kMaterialTextStartOffset + [tableView contentLeftPadding], - kContentLineHeight - kVerticalTextPadding); + origin = NSMakePoint( + kMaterialTextStartOffset + [tableView contentLeftPadding], + [OmniboxPopupCell getContentTextHeight] - GetVerticalMargin()); CGFloat imageSize = [tableView answerLineHeight]; NSRect imageRect = NSMakeRect(NSMinX(cellFrame) + origin.x, NSMinY(cellFrame) + origin.y, @@ -519,7 +531,7 @@ respectFlipped:YES hints:nil]; if ([cellData answerImage]) { - origin.x += imageSize + kMaterialVerticalImagePadding; + origin.x += imageSize + kMaterialImageXOffset; // Have to nudge the baseline down 1pt in Material Design for the text // that follows, so that it's the same as the bottom of the image. @@ -683,4 +695,9 @@ return NSWidth(cellFrame) - kMaterialTextStartOffset; } ++ (CGFloat)getContentTextHeight { + constexpr CGFloat kDefaultTextHeight = 19; + return kDefaultTextHeight + 2 * GetVerticalMargin(); +} + @end
diff --git a/chrome/browser/ui/cocoa/omnibox/omnibox_popup_matrix.mm b/chrome/browser/ui/cocoa/omnibox/omnibox_popup_matrix.mm index dd21664..ca66db2 100644 --- a/chrome/browser/ui/cocoa/omnibox/omnibox_popup_matrix.mm +++ b/chrome/browser/ui/cocoa/omnibox/omnibox_popup_matrix.mm
@@ -106,7 +106,7 @@ } - (CGFloat)tableView:(NSTableView*)tableView heightOfRow:(NSInteger)row { - CGFloat height = kContentLineHeight; + CGFloat height = [OmniboxPopupCell getContentTextHeight]; if ([[array_ objectAtIndex:row] isAnswer]) { OmniboxPopupMatrix* matrix = base::mac::ObjCCastStrict<OmniboxPopupMatrix>(tableView);
diff --git a/chrome/browser/ui/views/chrome_cleaner_dialog_browsertest.cc b/chrome/browser/ui/views/chrome_cleaner_dialog_browsertest_win.cc similarity index 91% rename from chrome/browser/ui/views/chrome_cleaner_dialog_browsertest.cc rename to chrome/browser/ui/views/chrome_cleaner_dialog_browsertest_win.cc index e5f5a56..48c51375 100644 --- a/chrome/browser/ui/views/chrome_cleaner_dialog_browsertest.cc +++ b/chrome/browser/ui/views/chrome_cleaner_dialog_browsertest_win.cc
@@ -2,10 +2,10 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "chrome/browser/ui/views/chrome_cleaner_dialog.h" +#include "chrome/browser/ui/views/chrome_cleaner_dialog_win.h" #include "base/macros.h" -#include "chrome/browser/safe_browsing/chrome_cleaner/chrome_cleaner_dialog_controller.h" +#include "chrome/browser/safe_browsing/chrome_cleaner/chrome_cleaner_dialog_controller_win.h" #include "chrome/browser/ui/browser.h" #include "chrome/browser/ui/browser_dialogs.h" #include "chrome/browser/ui/test/test_browser_dialog.h"
diff --git a/chrome/browser/ui/views/chrome_cleaner_dialog.cc b/chrome/browser/ui/views/chrome_cleaner_dialog_win.cc similarity index 95% rename from chrome/browser/ui/views/chrome_cleaner_dialog.cc rename to chrome/browser/ui/views/chrome_cleaner_dialog_win.cc index e019847..c6cf1b3 100644 --- a/chrome/browser/ui/views/chrome_cleaner_dialog.cc +++ b/chrome/browser/ui/views/chrome_cleaner_dialog_win.cc
@@ -2,10 +2,10 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "chrome/browser/ui/views/chrome_cleaner_dialog.h" +#include "chrome/browser/ui/views/chrome_cleaner_dialog_win.h" #include "base/strings/string16.h" -#include "chrome/browser/safe_browsing/chrome_cleaner/chrome_cleaner_dialog_controller.h" +#include "chrome/browser/safe_browsing/chrome_cleaner/chrome_cleaner_dialog_controller_win.h" #include "chrome/browser/ui/browser.h" #include "chrome/browser/ui/browser_dialogs.h" #include "chrome/browser/ui/browser_window.h" @@ -104,7 +104,7 @@ views::View* ChromeCleanerDialog::CreateExtraView() { return views::MdTextButton::CreateSecondaryUiButton( - this, controller_->GetAdvancedButtonLabel()); + this, controller_->GetDetailsButtonLabel()); } bool ChromeCleanerDialog::Accept() { @@ -146,7 +146,7 @@ // TODO(alito): Navigate to the webui version of the Chrome Cleaner UI when // that is implemented. if (controller_) { - controller_->AdvancedButtonClicked(); + controller_->DetailsButtonClicked(); controller_ = nullptr; } GetWidget()->Close();
diff --git a/chrome/browser/ui/views/chrome_cleaner_dialog.h b/chrome/browser/ui/views/chrome_cleaner_dialog_win.h similarity index 92% rename from chrome/browser/ui/views/chrome_cleaner_dialog.h rename to chrome/browser/ui/views/chrome_cleaner_dialog_win.h index bc62092..4811919 100644 --- a/chrome/browser/ui/views/chrome_cleaner_dialog.h +++ b/chrome/browser/ui/views/chrome_cleaner_dialog_win.h
@@ -2,8 +2,8 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#ifndef CHROME_BROWSER_UI_VIEWS_CHROME_CLEANER_DIALOG_H_ -#define CHROME_BROWSER_UI_VIEWS_CHROME_CLEANER_DIALOG_H_ +#ifndef CHROME_BROWSER_UI_VIEWS_CHROME_CLEANER_DIALOG_WIN_H_ +#define CHROME_BROWSER_UI_VIEWS_CHROME_CLEANER_DIALOG_WIN_H_ #include <memory> @@ -67,4 +67,4 @@ DISALLOW_COPY_AND_ASSIGN(ChromeCleanerDialog); }; -#endif // CHROME_BROWSER_UI_VIEWS_CHROME_CLEANER_DIALOG_H_ +#endif // CHROME_BROWSER_UI_VIEWS_CHROME_CLEANER_DIALOG_WIN_H_
diff --git a/chrome/browser/ui/views/download/download_feedback_dialog_view.cc b/chrome/browser/ui/views/download/download_feedback_dialog_view.cc index 1ba26514..5e80388 100644 --- a/chrome/browser/ui/views/download/download_feedback_dialog_view.cc +++ b/chrome/browser/ui/views/download/download_feedback_dialog_view.cc
@@ -15,7 +15,7 @@ #include "chrome/grit/generated_resources.h" #include "components/constrained_window/constrained_window_views.h" #include "components/prefs/pref_service.h" -#include "components/safe_browsing_db/safe_browsing_prefs.h" +#include "components/safe_browsing/common/safe_browsing_prefs.h" #include "components/strings/grit/components_strings.h" #include "content/public/browser/page_navigator.h" #include "ui/base/l10n/l10n_util.h"
diff --git a/chrome/browser/ui/views/download/download_item_view.cc b/chrome/browser/ui/views/download/download_item_view.cc index ac6bae1..ebbd481a 100644 --- a/chrome/browser/ui/views/download/download_item_view.cc +++ b/chrome/browser/ui/views/download/download_item_view.cc
@@ -41,7 +41,7 @@ #include "chrome/common/pref_names.h" #include "chrome/grit/generated_resources.h" #include "components/prefs/pref_service.h" -#include "components/safe_browsing_db/safe_browsing_prefs.h" +#include "components/safe_browsing/common/safe_browsing_prefs.h" #include "content/public/browser/download_danger_type.h" #include "third_party/icu/source/common/unicode/uchar.h" #include "ui/accessibility/ax_node_data.h"
diff --git a/chrome/browser/ui/views/find_bar_host.cc b/chrome/browser/ui/views/find_bar_host.cc index 87372a11..81c33c9 100644 --- a/chrome/browser/ui/views/find_bar_host.cc +++ b/chrome/browser/ui/views/find_bar_host.cc
@@ -63,7 +63,9 @@ // input. Otherwise Up and Down arrow key strokes get eaten. "Nom Nom Nom". contents->ClearFocusedElement(); NativeWebKeyboardEvent event(key_event); - contents->GetRenderViewHost()->GetWidget()->ForwardKeyboardEvent(event); + contents->GetRenderViewHost() + ->GetWidget() + ->ForwardKeyboardEventWithLatencyInfo(event, *key_event.latency()); return true; }
diff --git a/chrome/browser/ui/views/payments/contact_info_editor_view_controller.cc b/chrome/browser/ui/views/payments/contact_info_editor_view_controller.cc index 926ef21..f9febb9 100644 --- a/chrome/browser/ui/views/payments/contact_info_editor_view_controller.cc +++ b/chrome/browser/ui/views/payments/contact_info_editor_view_controller.cc
@@ -27,9 +27,13 @@ PaymentRequestState* state, PaymentRequestDialogView* dialog, BackNavigationType back_navigation_type, + base::OnceClosure on_edited, + base::OnceCallback<void(const autofill::AutofillProfile&)> on_added, autofill::AutofillProfile* profile) : EditorViewController(spec, state, dialog, back_navigation_type), - profile_to_edit_(profile) {} + profile_to_edit_(profile), + on_edited_(std::move(on_edited)), + on_added_(std::move(on_added)) {} ContactInfoEditorViewController::~ContactInfoEditorViewController() {} @@ -76,12 +80,15 @@ PopulateProfile(profile_to_edit_); state()->GetPersonalDataManager()->UpdateProfile(*profile_to_edit_); state()->profile_comparator()->Invalidate(*profile_to_edit_); + std::move(on_edited_).Run(); + on_added_.Reset(); } else { std::unique_ptr<autofill::AutofillProfile> profile = base::MakeUnique<autofill::AutofillProfile>(); PopulateProfile(profile.get()); state()->GetPersonalDataManager()->AddProfile(*profile); - // TODO(crbug.com/712224): Add to profile cache in state_. + std::move(on_added_).Run(*profile); + on_edited_.Reset(); } return true; }
diff --git a/chrome/browser/ui/views/payments/contact_info_editor_view_controller.h b/chrome/browser/ui/views/payments/contact_info_editor_view_controller.h index b50ec9d..5a0ab4a 100644 --- a/chrome/browser/ui/views/payments/contact_info_editor_view_controller.h +++ b/chrome/browser/ui/views/payments/contact_info_editor_view_controller.h
@@ -25,11 +25,14 @@ // Does not take ownership of the arguments, which should outlive this object. // Passing nullptr as |profile| indicates that we are editing a new profile; // other arguments should never be null. - ContactInfoEditorViewController(PaymentRequestSpec* spec, - PaymentRequestState* state, - PaymentRequestDialogView* dialog, - BackNavigationType back_navigation_type, - autofill::AutofillProfile* profile); + ContactInfoEditorViewController( + PaymentRequestSpec* spec, + PaymentRequestState* state, + PaymentRequestDialogView* dialog, + BackNavigationType back_navigation_type, + base::OnceClosure on_edited, + base::OnceCallback<void(const autofill::AutofillProfile&)> on_added, + autofill::AutofillProfile* profile); ~ContactInfoEditorViewController() override; // EditorViewController: @@ -51,11 +54,16 @@ // Uses the values in the UI fields to populate the corresponding values in // |profile|. void PopulateProfile(autofill::AutofillProfile* profile); - bool GetSheetId(DialogViewID* sheet_id) override; autofill::AutofillProfile* profile_to_edit_; + // Called when |profile_to_edit_| was successfully edited. + base::OnceClosure on_edited_; + // Called when a new profile was added. The const reference is short-lived, + // and the callee should make a copy. + base::OnceCallback<void(const autofill::AutofillProfile&)> on_added_; + class ContactInfoValidationDelegate : public ValidationDelegate { public: ContactInfoValidationDelegate(const EditorField& field,
diff --git a/chrome/browser/ui/views/payments/contact_info_editor_view_controller_browsertest.cc b/chrome/browser/ui/views/payments/contact_info_editor_view_controller_browsertest.cc index e656af7..dc2cf24 100644 --- a/chrome/browser/ui/views/payments/contact_info_editor_view_controller_browsertest.cc +++ b/chrome/browser/ui/views/payments/contact_info_editor_view_controller_browsertest.cc
@@ -70,6 +70,11 @@ EXPECT_EQ(base::ASCIIToUTF16(kEmailAddress), profile->GetInfo(autofill::AutofillType(autofill::EMAIL_ADDRESS), GetLocale())); + + PaymentRequest* request = GetPaymentRequests(GetActiveWebContents()).front(); + EXPECT_EQ(1U, request->state()->contact_profiles().size()); + EXPECT_EQ(request->state()->contact_profiles().back(), + request->state()->selected_contact_profile()); } IN_PROC_BROWSER_TEST_F(PaymentRequestContactInfoEditorTest, @@ -213,4 +218,60 @@ GetLocale())); } +IN_PROC_BROWSER_TEST_F(PaymentRequestContactInfoEditorTest, + ModifyExistingSelectsIt) { + autofill::PersonalDataManager* personal_data_manager = GetDataManager(); + personal_data_manager->AddObserver(&personal_data_observer_); + + autofill::AutofillProfile incomplete_profile; + incomplete_profile.SetInfo(autofill::AutofillType(autofill::NAME_FULL), + base::ASCIIToUTF16(kNameFull), GetLocale()); + AddAutofillProfile(incomplete_profile); + + autofill::AutofillProfile other_incomplete_profile; + other_incomplete_profile.SetInfo(autofill::AutofillType(autofill::NAME_FULL), + base::ASCIIToUTF16("other"), GetLocale()); + AddAutofillProfile(other_incomplete_profile); + + InvokePaymentRequestUI(); + OpenContactInfoScreen(); + + PaymentRequest* request = GetPaymentRequests(GetActiveWebContents()).front(); + EXPECT_EQ(request->state()->contact_profiles().front(), + request->state()->selected_contact_profile()); + + views::View* list_view = dialog_view()->GetViewByID( + static_cast<int>(DialogViewID::CONTACT_INFO_SHEET_LIST_VIEW)); + DCHECK(list_view); + ClickOnDialogViewAndWait(list_view->child_at(1)); + + SetEditorTextfieldValue(base::ASCIIToUTF16(kPhoneNumber), + autofill::PHONE_HOME_WHOLE_NUMBER); + SetEditorTextfieldValue(base::ASCIIToUTF16(kEmailAddress), + autofill::EMAIL_ADDRESS); + + // Wait until the web database has been updated and the notification sent. + base::RunLoop save_data_loop; + EXPECT_CALL(personal_data_observer_, OnPersonalDataChanged()) + .WillOnce(QuitMessageLoop(&save_data_loop)); + ClickOnDialogViewAndWait(DialogViewID::EDITOR_SAVE_BUTTON); + save_data_loop.Run(); + + ASSERT_EQ(2UL, personal_data_manager->GetProfiles().size()); + autofill::AutofillProfile* profile = personal_data_manager->GetProfiles()[0]; + DCHECK(profile); + + EXPECT_EQ(base::ASCIIToUTF16(kPhoneNumber), + profile->GetInfo( + autofill::AutofillType(autofill::PHONE_HOME_WHOLE_NUMBER), + GetLocale())); + EXPECT_EQ(base::ASCIIToUTF16(kEmailAddress), + profile->GetInfo(autofill::AutofillType(autofill::EMAIL_ADDRESS), + GetLocale())); + + EXPECT_EQ(2U, request->state()->contact_profiles().size()); + EXPECT_EQ(request->state()->contact_profiles().back(), + request->state()->selected_contact_profile()); +} + } // namespace payments
diff --git a/chrome/browser/ui/views/payments/payment_request_dialog_view.cc b/chrome/browser/ui/views/payments/payment_request_dialog_view.cc index 12c798d..d1f472f 100644 --- a/chrome/browser/ui/views/payments/payment_request_dialog_view.cc +++ b/chrome/browser/ui/views/payments/payment_request_dialog_view.cc
@@ -277,13 +277,16 @@ void PaymentRequestDialogView::ShowContactInfoEditor( BackNavigationType back_navigation_type, + base::OnceClosure on_edited, + base::OnceCallback<void(const autofill::AutofillProfile&)> on_added, autofill::AutofillProfile* profile) { - view_stack_->Push(CreateViewAndInstallController( - base::MakeUnique<ContactInfoEditorViewController>( - request_->spec(), request_->state(), this, - back_navigation_type, profile), - &controller_map_), - /* animate = */ true); + view_stack_->Push( + CreateViewAndInstallController( + base::MakeUnique<ContactInfoEditorViewController>( + request_->spec(), request_->state(), this, back_navigation_type, + std::move(on_edited), std::move(on_added), profile), + &controller_map_), + /* animate = */ true); if (observer_for_testing_) observer_for_testing_->OnContactInfoEditorOpened(); }
diff --git a/chrome/browser/ui/views/payments/payment_request_dialog_view.h b/chrome/browser/ui/views/payments/payment_request_dialog_view.h index 4e18583..f793e84 100644 --- a/chrome/browser/ui/views/payments/payment_request_dialog_view.h +++ b/chrome/browser/ui/views/payments/payment_request_dialog_view.h
@@ -136,10 +136,16 @@ base::OnceCallback<void(const autofill::AutofillProfile&)> on_added, autofill::AutofillProfile* profile); // |profile| is the profile to be edited, or nullptr for adding a profile. + // |on_edited| is called when |profile| was successfully edited, and + // |on_added| is called when a new profile was added (the reference is + // short-lived; callee should make a copy of the profile object). // |back_navigation_type| identifies the type of navigation to execute once // the editor has completed successfully. - void ShowContactInfoEditor(BackNavigationType back_navigation_type, - autofill::AutofillProfile* profile = nullptr); + void ShowContactInfoEditor( + BackNavigationType back_navigation_type, + base::OnceClosure on_edited, + base::OnceCallback<void(const autofill::AutofillProfile&)> on_added, + autofill::AutofillProfile* profile = nullptr); void EditorViewUpdated(); void ShowCvcUnmaskPrompt(
diff --git a/chrome/browser/ui/views/payments/payment_sheet_view_controller.cc b/chrome/browser/ui/views/payments/payment_sheet_view_controller.cc index 6f5a599..3e83ac61 100644 --- a/chrome/browser/ui/views/payments/payment_sheet_view_controller.cc +++ b/chrome/browser/ui/views/payments/payment_sheet_view_controller.cc
@@ -526,7 +526,12 @@ case static_cast<int>( PaymentSheetViewControllerTags::ADD_CONTACT_INFO_BUTTON): - dialog()->ShowContactInfoEditor(BackNavigationType::kPaymentSheet); + dialog()->ShowContactInfoEditor( + BackNavigationType::kPaymentSheet, + /*on_edited=*/base::OnceClosure(), // This is always an add. + /*on_added=*/ + base::BindOnce(&PaymentRequestState::AddAutofillContactProfile, + base::Unretained(state()), /*selected=*/true)); break; case static_cast<int>(
diff --git a/chrome/browser/ui/views/payments/profile_list_view_controller.cc b/chrome/browser/ui/views/payments/profile_list_view_controller.cc index f30561a6..657d5a6 100644 --- a/chrome/browser/ui/views/payments/profile_list_view_controller.cc +++ b/chrome/browser/ui/views/payments/profile_list_view_controller.cc
@@ -245,7 +245,15 @@ } void ShowEditor(autofill::AutofillProfile* profile) override { - dialog()->ShowContactInfoEditor(BackNavigationType::kPaymentSheet, profile); + dialog()->ShowContactInfoEditor( + BackNavigationType::kPaymentSheet, + /*on_edited=*/ + base::BindOnce(&PaymentRequestState::SetSelectedContactProfile, + base::Unretained(state()), profile), + /*on_added=*/ + base::BindOnce(&PaymentRequestState::AddAutofillContactProfile, + base::Unretained(state()), /*selected=*/true), + profile); } autofill::AutofillProfile* GetSelectedProfile() override {
diff --git a/chrome/browser/ui/webui/options/browser_options_handler.cc b/chrome/browser/ui/webui/options/browser_options_handler.cc index e35875c..cff93a3 100644 --- a/chrome/browser/ui/webui/options/browser_options_handler.cc +++ b/chrome/browser/ui/webui/options/browser_options_handler.cc
@@ -84,7 +84,7 @@ #include "components/prefs/scoped_user_pref_update.h" #include "components/proximity_auth/switches.h" #include "components/proxy_config/proxy_config_pref_names.h" -#include "components/safe_browsing_db/safe_browsing_prefs.h" +#include "components/safe_browsing/common/safe_browsing_prefs.h" #include "components/search_engines/template_url.h" #include "components/search_engines/template_url_service.h" #include "components/signin/core/browser/signin_manager.h"
diff --git a/chrome/browser/ui/webui/settings/md_settings_localized_strings_provider.cc b/chrome/browser/ui/webui/settings/md_settings_localized_strings_provider.cc index 9cd9616..191a685 100644 --- a/chrome/browser/ui/webui/settings/md_settings_localized_strings_provider.cc +++ b/chrome/browser/ui/webui/settings/md_settings_localized_strings_provider.cc
@@ -27,7 +27,7 @@ #include "components/autofill/core/common/autofill_constants.h" #include "components/google/core/browser/google_util.h" #include "components/password_manager/core/browser/password_manager_constants.h" -#include "components/safe_browsing_db/safe_browsing_prefs.h" +#include "components/safe_browsing/common/safe_browsing_prefs.h" #include "components/strings/grit/components_strings.h" #include "components/subresource_filter/core/browser/subresource_filter_features.h" #include "content/public/browser/web_ui_data_source.h"
diff --git a/chrome/browser/ui/webui/settings/safe_browsing_handler.cc b/chrome/browser/ui/webui/settings/safe_browsing_handler.cc index 1490781..a77b474 100644 --- a/chrome/browser/ui/webui/settings/safe_browsing_handler.cc +++ b/chrome/browser/ui/webui/settings/safe_browsing_handler.cc
@@ -8,7 +8,7 @@ #include "base/bind_helpers.h" #include "base/values.h" #include "components/prefs/pref_service.h" -#include "components/safe_browsing_db/safe_browsing_prefs.h" +#include "components/safe_browsing/common/safe_browsing_prefs.h" #include "content/public/browser/web_ui.h" namespace settings {
diff --git a/chrome/test/BUILD.gn b/chrome/test/BUILD.gn index 42efbabfc..028825f 100644 --- a/chrome/test/BUILD.gn +++ b/chrome/test/BUILD.gn
@@ -1627,6 +1627,7 @@ "../browser/ui/toolbar/mock_component_toolbar_actions_factory.cc", "../browser/ui/toolbar/mock_component_toolbar_actions_factory.h", "../browser/ui/update_chrome_dialog_browsertest.cc", + "../browser/ui/views/chrome_cleaner_dialog_browsertest_win.cc", "../browser/ui/views/hung_renderer_view_browsertest.cc", "../browser/ui/webui/bidi_checker_web_ui_test.cc", "../browser/ui/webui/bidi_checker_web_ui_test.h", @@ -2424,7 +2425,6 @@ if (is_win) { sources += [ "../browser/extensions/api/networking_private/networking_private_credentials_getter_browsertest.cc", - "../browser/ui/views/chrome_cleaner_dialog_browsertest.cc", "../browser/ui/views/settings_reset_prompt_dialog_browsertest.cc", ] }
diff --git a/chrome/test/android/javatests/src/org/chromium/chrome/test/util/browser/notifications/MockNotificationManagerProxy.java b/chrome/test/android/javatests/src/org/chromium/chrome/test/util/browser/notifications/MockNotificationManagerProxy.java index 25e43b42..06de368 100644 --- a/chrome/test/android/javatests/src/org/chromium/chrome/test/util/browser/notifications/MockNotificationManagerProxy.java +++ b/chrome/test/android/javatests/src/org/chromium/chrome/test/util/browser/notifications/MockNotificationManagerProxy.java
@@ -7,13 +7,16 @@ import android.app.Notification; import org.chromium.chrome.browser.notifications.NotificationManagerProxy; +import org.chromium.chrome.browser.notifications.channels.Channel; import org.chromium.chrome.browser.notifications.channels.ChannelDefinitions; import java.util.ArrayList; +import java.util.HashSet; import java.util.Iterator; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; +import java.util.Set; import javax.annotation.Nullable; @@ -23,9 +26,8 @@ */ public class MockNotificationManagerProxy implements NotificationManagerProxy { private static final String KEY_SEPARATOR = ":"; - private List<ChannelDefinitions.Channel> mChannels; - private List<ChannelDefinitions.ChannelGroup> mNotificationChannelGroups; - + private List<Channel> mChannels; + private Set<ChannelDefinitions.ChannelGroup> mNotificationChannelGroups; /** * Holds a notification and the arguments passed to #notify and #cancel. */ @@ -50,7 +52,7 @@ mNotifications = new LinkedHashMap<>(); mMutationCount = 0; mChannels = new ArrayList<>(); - mNotificationChannelGroups = new ArrayList<>(); + mNotificationChannelGroups = new HashSet<>(); } /** @@ -61,7 +63,7 @@ * @return List of the managed notifications. */ public List<NotificationEntry> getNotifications() { - return new ArrayList<NotificationEntry>(mNotifications.values()); + return new ArrayList<>(mNotifications.values()); } /** @@ -97,37 +99,29 @@ } @Override - public void createNotificationChannel(ChannelDefinitions.Channel channel) { + public void createNotificationChannel(Channel channel) { mChannels.add(channel); } - public List<ChannelDefinitions.Channel> getChannels() { - return mChannels; - } - @Override public void createNotificationChannelGroup(ChannelDefinitions.ChannelGroup channelGroup) { mNotificationChannelGroups.add(channelGroup); } + @Override + public List<Channel> getNotificationChannels() { + return mChannels; + } + public List<ChannelDefinitions.ChannelGroup> getNotificationChannelGroups() { - return mNotificationChannelGroups; + return new ArrayList<>(mNotificationChannelGroups); } @Override - public List<String> getNotificationChannelIds() { - List<String> channelIds = new ArrayList<>(); - for (ChannelDefinitions.Channel channel : mChannels) { - channelIds.add(channel.mId); - } - return channelIds; - } - - @Override - public void deleteNotificationChannel(@ChannelDefinitions.ChannelId String id) { - for (Iterator<ChannelDefinitions.Channel> it = mChannels.iterator(); it.hasNext();) { - ChannelDefinitions.Channel channel = it.next(); - if (id.equals(channel.mId)) it.remove(); + public void deleteNotificationChannel(String id) { + for (Iterator<Channel> it = mChannels.iterator(); it.hasNext();) { + Channel channel = it.next(); + if (id.equals(channel.getId())) it.remove(); } }
diff --git a/chrome/test/base/testing_io_thread_state.cc b/chrome/test/base/testing_io_thread_state.cc index 8e6ab86..c3c1205c 100644 --- a/chrome/test/base/testing_io_thread_state.cc +++ b/chrome/test/base/testing_io_thread_state.cc
@@ -96,8 +96,7 @@ void TestingIOThreadState::Shutdown(const base::Closure& done) { DCHECK_CURRENTLY_ON(BrowserThread::IO); - delete io_thread_state_->globals(); - io_thread_state_->SetGlobalsForTesting(NULL); + io_thread_state_->CleanUp(); done.Run(); }
diff --git a/components/BUILD.gn b/components/BUILD.gn index 820846ac..987c03e 100644 --- a/components/BUILD.gn +++ b/components/BUILD.gn
@@ -209,6 +209,7 @@ "//components/policy/core/browser:unit_tests", "//components/policy/core/common:unit_tests", "//components/precache/content:unit_tests", + "//components/safe_browsing/common:unit_tests", "//components/safe_browsing/password_protection:password_protection_unittest", "//components/safe_browsing_db:unit_tests", "//components/safe_json:unit_tests",
diff --git a/components/handoff/handoff_manager.mm b/components/handoff/handoff_manager.mm index 8300210..cdcb8f1 100644 --- a/components/handoff/handoff_manager.mm +++ b/components/handoff/handoff_manager.mm
@@ -5,7 +5,7 @@ #include "components/handoff/handoff_manager.h" #include "base/logging.h" -#include "base/mac/objc_release_properties.h" +#include "base/mac/objc_property_releaser.h" #include "base/mac/scoped_nsobject.h" #include "net/base/mac/url_conversions.h" @@ -34,6 +34,7 @@ @end @implementation HandoffManager { + base::mac::ObjCPropertyReleaser _propertyReleaser_HandoffManager; GURL _activeURL; NSUserActivity* _userActivity; handoff::Origin _origin; @@ -52,6 +53,7 @@ - (instancetype)init { self = [super init]; if (self) { + _propertyReleaser_HandoffManager.Init(self, [HandoffManager class]); #if defined(OS_MACOSX) && !defined(OS_IOS) _origin = handoff::ORIGIN_MAC; #elif defined(OS_IOS) @@ -63,11 +65,6 @@ return self; } -- (void)dealloc { - base::mac::ReleaseProperties(self); - [super dealloc]; -} - - (void)updateActiveURL:(const GURL&)url { #if defined(OS_MACOSX) && !defined(OS_IOS) // Handoff is only available on OSX 10.10+.
diff --git a/components/offline_pages/core/offline_page_model_query.cc b/components/offline_pages/core/offline_page_model_query.cc index 5fff06f..382e20b 100644 --- a/components/offline_pages/core/offline_page_model_query.cc +++ b/components/offline_pages/core/offline_page_model_query.cc
@@ -68,6 +68,12 @@ return *this; } +OfflinePageModelQueryBuilder& OfflinePageModelQueryBuilder::RequireNamespace( + const std::string& name_space) { + name_space_ = base::MakeUnique<std::string>(name_space); + return *this; +} + std::unique_ptr<OfflinePageModelQuery> OfflinePageModelQueryBuilder::Build( ClientPolicyController* controller) { DCHECK(controller); @@ -89,7 +95,15 @@ std::vector<std::string> allowed_namespaces; bool uses_namespace_restrictions = false; - for (auto& name_space : controller->GetAllNamespaces()) { + std::vector<std::string> namespaces; + if (name_space_) { + uses_namespace_restrictions = true; + namespaces.push_back(*name_space_); + } else { + namespaces = controller->GetAllNamespaces(); + } + + for (auto& name_space : namespaces) { // If any exclusion requirements exist, and the namespace matches one of // those excluded by policy, skip adding it to |allowed_namespaces|. if ((removed_on_cache_reset_ == Requirement::EXCLUDE_MATCHING &&
diff --git a/components/offline_pages/core/offline_page_model_query.h b/components/offline_pages/core/offline_page_model_query.h index ae79913a..4107b39 100644 --- a/components/offline_pages/core/offline_page_model_query.h +++ b/components/offline_pages/core/offline_page_model_query.h
@@ -113,6 +113,9 @@ OfflinePageModelQueryBuilder& RequireRestrictedToOriginalTab( Requirement original_tab); + // Only include results from a single namespace. + OfflinePageModelQueryBuilder& RequireNamespace(const std::string& name_space); + // Builds the query using the namespace policies provided by |controller| // This resets the internal state. |controller| should not be |nullptr|. std::unique_ptr<OfflinePageModelQuery> Build( @@ -135,6 +138,8 @@ Requirement shown_as_recently_visited_site_ = Requirement::UNSET; Requirement restricted_to_original_tab_ = Requirement::UNSET; + std::unique_ptr<std::string> name_space_; + DISALLOW_COPY_AND_ASSIGN(OfflinePageModelQueryBuilder); };
diff --git a/components/offline_pages/core/offline_page_model_query_unittest.cc b/components/offline_pages/core/offline_page_model_query_unittest.cc index fad1c62..01eb27b6a 100644 --- a/components/offline_pages/core/offline_page_model_query_unittest.cc +++ b/components/offline_pages/core/offline_page_model_query_unittest.cc
@@ -437,4 +437,19 @@ EXPECT_FALSE(query->Matches(recent_page())); } +TEST_F(OfflinePageModelQueryTest, RequireNamespace) { + builder_.RequireNamespace(kDefaultNamespace); + std::unique_ptr<OfflinePageModelQuery> query = builder_.Build(&policy_); + auto restriction = query->GetRestrictedToNamespaces(); + std::set<std::string> namespaces_allowed = restriction.second; + bool restricted_to_namespaces = restriction.first; + EXPECT_TRUE(restricted_to_namespaces); + EXPECT_EQ(1U, namespaces_allowed.size()); + EXPECT_TRUE(namespaces_allowed.find(kDefaultNamespace) != + namespaces_allowed.end()); + + EXPECT_TRUE(query->Matches(kTestItem1)); + EXPECT_FALSE(query->Matches(test_namespace_page())); +} + } // namespace offline_pages
diff --git a/components/payments/content/payment_request_state.cc b/components/payments/content/payment_request_state.cc index fb728d1..1236b70 100644 --- a/components/payments/content/payment_request_state.cc +++ b/components/payments/content/payment_request_state.cc
@@ -166,6 +166,18 @@ SetSelectedShippingProfile(new_cached_profile); } +void PaymentRequestState::AddAutofillContactProfile( + bool selected, + const autofill::AutofillProfile& profile) { + profile_cache_.push_back( + base::MakeUnique<autofill::AutofillProfile>(profile)); + autofill::AutofillProfile* new_cached_profile = profile_cache_.back().get(); + contact_profiles_.push_back(new_cached_profile); + + if (selected) + SetSelectedContactProfile(new_cached_profile); +} + void PaymentRequestState::SetSelectedShippingOption( const std::string& shipping_option_id) { spec_->StartWaitingForUpdateWith(
diff --git a/components/payments/content/payment_request_state.h b/components/payments/content/payment_request_state.h index 66241bd..72ea70ac5a 100644 --- a/components/payments/content/payment_request_state.h +++ b/components/payments/content/payment_request_state.h
@@ -149,6 +149,12 @@ void AddAutofillShippingProfile(bool selected, const autofill::AutofillProfile& profile); + // Creates and adds an AutofillProfile as a contact profile, which makes a + // copy of |profile|. |selected| indicates if the newly-created shipping + // profile should be selected, after which observers will be notified. + void AddAutofillContactProfile(bool selected, + const autofill::AutofillProfile& profile); + // Setters to change the selected information. Will have the side effect of // recomputing "is ready to pay" and notify observers. void SetSelectedShippingOption(const std::string& shipping_option_id);
diff --git a/components/prefs/json_pref_store.cc b/components/prefs/json_pref_store.cc index cf4d2a3..7716082 100644 --- a/components/prefs/json_pref_store.cc +++ b/components/prefs/json_pref_store.cc
@@ -143,13 +143,13 @@ JsonPrefStore::JsonPrefStore( const base::FilePath& pref_filename, - const scoped_refptr<base::SequencedTaskRunner>& sequenced_task_runner, + scoped_refptr<base::SequencedTaskRunner> sequenced_task_runner, std::unique_ptr<PrefFilter> pref_filter) : path_(pref_filename), - sequenced_task_runner_(sequenced_task_runner), + sequenced_task_runner_(std::move(sequenced_task_runner)), prefs_(new base::DictionaryValue()), read_only_(false), - writer_(pref_filename, sequenced_task_runner), + writer_(pref_filename, sequenced_task_runner_), pref_filter_(std::move(pref_filter)), initialized_(false), filtering_in_progress_(false),
diff --git a/components/prefs/json_pref_store.h b/components/prefs/json_pref_store.h index 6284b8d5..b298d30 100644 --- a/components/prefs/json_pref_store.h +++ b/components/prefs/json_pref_store.h
@@ -19,9 +19,11 @@ #include "base/macros.h" #include "base/memory/weak_ptr.h" #include "base/observer_list.h" +#include "base/task_scheduler/post_task.h" #include "base/threading/non_thread_safe.h" #include "components/prefs/base_prefs_export.h" #include "components/prefs/persistent_pref_store.h" +#include "components/prefs/pref_filter.h" class PrefFilter; @@ -62,13 +64,18 @@ const base::FilePath& pref_filename, base::SequencedWorkerPool* worker_pool); - // |sequenced_task_runner| must be a shutdown-blocking task runner, ideally - // created by the GetTaskRunnerForFile() method above. - // |pref_filename| is the path to the file to read prefs from. - JsonPrefStore( - const base::FilePath& pref_filename, - const scoped_refptr<base::SequencedTaskRunner>& sequenced_task_runner, - std::unique_ptr<PrefFilter> pref_filter); + // |pref_filename| is the path to the file to read prefs from. It is incorrect + // to create multiple JsonPrefStore with the same |pref_filename|. + // |sequenced_task_runner| is used for asynchronous reads and writes. It must + // have the base::TaskShutdownBehavior::BLOCK_SHUTDOWN and base::MayBlock() + // traits. Unless external tasks need to run on the same sequence as + // JsonPrefStore tasks, keep the default value. + JsonPrefStore(const base::FilePath& pref_filename, + scoped_refptr<base::SequencedTaskRunner> sequenced_task_runner = + base::CreateSequencedTaskRunnerWithTraits( + {base::MayBlock(), + base::TaskShutdownBehavior::BLOCK_SHUTDOWN}), + std::unique_ptr<PrefFilter> pref_filter = nullptr); // PrefStore overrides: bool GetValue(const std::string& key,
diff --git a/components/proxy_config/pref_proxy_config_tracker.h b/components/proxy_config/pref_proxy_config_tracker.h index d51abc8a..77e2e36c 100644 --- a/components/proxy_config/pref_proxy_config_tracker.h +++ b/components/proxy_config/pref_proxy_config_tracker.h
@@ -29,7 +29,7 @@ // before DetachFromPrefService was called. Takes ownership of the passed // |base_service|, which can be NULL. This |base_service| provides the proxy // settings of the OS (except of ChromeOS). This must be called on the - // UI thread. + // UI thread. May only be called once on a PrefProxyConfigTracker. virtual std::unique_ptr<net::ProxyConfigService> CreateTrackingProxyConfigService( std::unique_ptr<net::ProxyConfigService> base_service) = 0;
diff --git a/components/proxy_config/pref_proxy_config_tracker_impl.cc b/components/proxy_config/pref_proxy_config_tracker_impl.cc index f8077aa..0fead147 100644 --- a/components/proxy_config/pref_proxy_config_tracker_impl.cc +++ b/components/proxy_config/pref_proxy_config_tracker_impl.cc
@@ -24,10 +24,12 @@ //============================= ProxyConfigServiceImpl ======================= ProxyConfigServiceImpl::ProxyConfigServiceImpl( - net::ProxyConfigService* base_service) - : base_service_(base_service), - pref_config_state_(ProxyPrefs::CONFIG_UNSET), - pref_config_read_pending_(true), + std::unique_ptr<net::ProxyConfigService> base_service, + ProxyPrefs::ConfigState initial_config_state, + const net::ProxyConfig& initial_config) + : base_service_(std::move(base_service)), + pref_config_state_(initial_config_state), + pref_config_(initial_config), registered_observer_(false) { // ProxyConfigServiceImpl is created on the UI thread, but used on the network // thread. @@ -54,9 +56,6 @@ ProxyConfigServiceImpl::GetLatestProxyConfig(net::ProxyConfig* config) { RegisterObserver(); - if (pref_config_read_pending_) - return net::ProxyConfigService::CONFIG_PENDING; - // Ask the base service if available. net::ProxyConfig system_config; ConfigAvailability system_availability = @@ -79,7 +78,6 @@ ProxyPrefs::ConfigState config_state, const net::ProxyConfig& config) { DCHECK(thread_checker_.CalledOnValidThread()); - pref_config_read_pending_ = false; pref_config_state_ = config_state; pref_config_ = config; @@ -109,7 +107,7 @@ // Check whether there is a proxy configuration defined by preferences. In // this case that proxy configuration takes precedence and the change event - // from the delegate proxy service can be disregarded. + // from the delegate proxy config service can be disregarded. if (!PrefProxyConfigTrackerImpl::PrefPrecedes(pref_config_state_)) { net::ProxyConfig actual_config; availability = GetLatestProxyConfig(&actual_config); @@ -149,12 +147,12 @@ std::unique_ptr<net::ProxyConfigService> PrefProxyConfigTrackerImpl::CreateTrackingProxyConfigService( std::unique_ptr<net::ProxyConfigService> base_service) { - proxy_config_service_impl_ = - new ProxyConfigServiceImpl(base_service.release()); + DCHECK(!proxy_config_service_impl_); + proxy_config_service_impl_ = new ProxyConfigServiceImpl( + std::move(base_service), config_state_, pref_config_); VLOG(1) << this << ": set chrome proxy config service to " << proxy_config_service_impl_; - if (proxy_config_service_impl_ && update_pending_) - OnProxyConfigChanged(config_state_, pref_config_); + update_pending_ = false; return std::unique_ptr<net::ProxyConfigService>(proxy_config_service_impl_); }
diff --git a/components/proxy_config/pref_proxy_config_tracker_impl.h b/components/proxy_config/pref_proxy_config_tracker_impl.h index ec42a7922..d8a22f6 100644 --- a/components/proxy_config/pref_proxy_config_tracker_impl.h +++ b/components/proxy_config/pref_proxy_config_tracker_impl.h
@@ -36,10 +36,9 @@ class ProxyConfigServiceImpl : public net::ProxyConfigService, public net::ProxyConfigService::Observer { public: - // Takes ownership of the passed |base_service|. - // GetLatestProxyConfig returns ConfigAvailability::CONFIG_PENDING until - // UpdateProxyConfig has been called. - explicit ProxyConfigServiceImpl(net::ProxyConfigService* base_service); + ProxyConfigServiceImpl(std::unique_ptr<net::ProxyConfigService> base_service, + ProxyPrefs::ConfigState initial_config_state, + const net::ProxyConfig& initial_config); ~ProxyConfigServiceImpl() override; // ProxyConfigService implementation: @@ -71,10 +70,6 @@ // Configuration as defined by prefs. net::ProxyConfig pref_config_; - // Flag that indicates that a PrefProxyConfigTracker needs to inform us - // about a proxy configuration before we may return any configuration. - bool pref_config_read_pending_; - // Indicates whether the base service registration is done. bool registered_observer_;
diff --git a/components/proxy_config/pref_proxy_config_tracker_impl_unittest.cc b/components/proxy_config/pref_proxy_config_tracker_impl_unittest.cc index b0fd11ed..b0fd3b5 100644 --- a/components/proxy_config/pref_proxy_config_tracker_impl_unittest.cc +++ b/components/proxy_config/pref_proxy_config_tracker_impl_unittest.cc
@@ -74,22 +74,22 @@ class PrefProxyConfigTrackerImplTest : public testing::Test { protected: - PrefProxyConfigTrackerImplTest() { + PrefProxyConfigTrackerImplTest() {} + + // Initializes the proxy config service. The delegate config service has the + // specified initial config availability. + void InitConfigService(net::ProxyConfigService::ConfigAvailability + delegate_config_availability) { pref_service_.reset(new TestingPrefServiceSimple()); PrefProxyConfigTrackerImpl::RegisterPrefs(pref_service_->registry()); fixed_config_.set_pac_url(GURL(kFixedPacUrl)); delegate_service_ = - new TestProxyConfigService(fixed_config_, - net::ProxyConfigService::CONFIG_VALID); + new TestProxyConfigService(fixed_config_, delegate_config_availability); proxy_config_tracker_.reset(new PrefProxyConfigTrackerImpl( pref_service_.get(), base::ThreadTaskRunnerHandle::Get())); proxy_config_service_ = proxy_config_tracker_->CreateTrackingProxyConfigService( std::unique_ptr<net::ProxyConfigService>(delegate_service_)); - // SetProxyConfigServiceImpl triggers update of initial prefs proxy - // config by tracker to chrome proxy config service, so flush all pending - // tasks so that tests start fresh. - base::RunLoop().RunUntilIdle(); } ~PrefProxyConfigTrackerImplTest() override { @@ -104,12 +104,11 @@ TestProxyConfigService* delegate_service_; // weak std::unique_ptr<net::ProxyConfigService> proxy_config_service_; net::ProxyConfig fixed_config_; - - private: std::unique_ptr<PrefProxyConfigTrackerImpl> proxy_config_tracker_; }; TEST_F(PrefProxyConfigTrackerImplTest, BaseConfiguration) { + InitConfigService(net::ProxyConfigService::CONFIG_VALID); net::ProxyConfig actual_config; EXPECT_EQ(net::ProxyConfigService::CONFIG_VALID, proxy_config_service_->GetLatestProxyConfig(&actual_config)); @@ -117,6 +116,7 @@ } TEST_F(PrefProxyConfigTrackerImplTest, DynamicPrefOverrides) { + InitConfigService(net::ProxyConfigService::CONFIG_VALID); pref_service_->SetManagedPref(proxy_config::prefs::kProxy, ProxyConfigDictionary::CreateFixedServers( "http://example.com:3128", std::string())); @@ -149,6 +149,7 @@ } TEST_F(PrefProxyConfigTrackerImplTest, Observers) { + InitConfigService(net::ProxyConfigService::CONFIG_VALID); const net::ProxyConfigService::ConfigAvailability CONFIG_VALID = net::ProxyConfigService::CONFIG_VALID; MockObserver observer; @@ -204,6 +205,7 @@ } TEST_F(PrefProxyConfigTrackerImplTest, Fallback) { + InitConfigService(net::ProxyConfigService::CONFIG_VALID); const net::ProxyConfigService::ConfigAvailability CONFIG_VALID = net::ProxyConfigService::CONFIG_VALID; MockObserver observer; @@ -257,6 +259,7 @@ } TEST_F(PrefProxyConfigTrackerImplTest, ExplicitSystemSettings) { + InitConfigService(net::ProxyConfigService::CONFIG_VALID); pref_service_->SetRecommendedPref(proxy_config::prefs::kProxy, ProxyConfigDictionary::CreateAutoDetect()); pref_service_->SetUserPref(proxy_config::prefs::kProxy, @@ -270,4 +273,34 @@ EXPECT_EQ(GURL(kFixedPacUrl), actual_config.pac_url()); } +// Test the case where the delegate service gets a config only after the service +// is created. +TEST_F(PrefProxyConfigTrackerImplTest, DelegateConfigServiceGetsConfigLate) { + InitConfigService(net::ProxyConfigService::CONFIG_PENDING); + + testing::StrictMock<MockObserver> observer; + proxy_config_service_->AddObserver(&observer); + + net::ProxyConfig actual_config; + EXPECT_EQ(net::ProxyConfigService::CONFIG_PENDING, + proxy_config_service_->GetLatestProxyConfig(&actual_config)); + + // When the delegate service gets the config, the other service should update + // its observers. + EXPECT_CALL(observer, + OnProxyConfigChanged(ProxyConfigMatches(fixed_config_), + net::ProxyConfigService::CONFIG_VALID)) + .Times(1); + delegate_service_->SetProxyConfig(fixed_config_, + net::ProxyConfigService::CONFIG_VALID); + + // Since no prefs were set, should just use the delegated config service's + // settings. + EXPECT_EQ(net::ProxyConfigService::CONFIG_VALID, + proxy_config_service_->GetLatestProxyConfig(&actual_config)); + EXPECT_EQ(GURL(kFixedPacUrl), actual_config.pac_url()); + + proxy_config_service_->RemoveObserver(&observer); +} + } // namespace
diff --git a/components/safe_browsing/BUILD.gn b/components/safe_browsing/BUILD.gn index ff80235e..c64922b 100644 --- a/components/safe_browsing/BUILD.gn +++ b/components/safe_browsing/BUILD.gn
@@ -24,8 +24,8 @@ ":base_ping_manager", "//base:base", "//base:i18n", + "//components/safe_browsing/common:safe_browsing_prefs", "//components/safe_browsing_db:database_manager", - "//components/safe_browsing_db:safe_browsing_prefs", "//components/security_interstitials/content:security_interstitial_page", "//components/security_interstitials/core:core", "//components/subresource_filter/content/browser:browser",
diff --git a/components/safe_browsing/base_blocking_page.cc b/components/safe_browsing/base_blocking_page.cc index 3b047b9..b1b57c6b 100644 --- a/components/safe_browsing/base_blocking_page.cc +++ b/components/safe_browsing/base_blocking_page.cc
@@ -9,7 +9,7 @@ #include "base/memory/ptr_util.h" #include "base/strings/string_number_conversions.h" #include "base/time/time.h" -#include "components/safe_browsing_db/safe_browsing_prefs.h" +#include "components/safe_browsing/common/safe_browsing_prefs.h" #include "components/security_interstitials/content/security_interstitial_controller_client.h" #include "components/security_interstitials/core/metrics_helper.h" #include "components/security_interstitials/core/safe_browsing_loud_error_ui.h"
diff --git a/components/safe_browsing/common/BUILD.gn b/components/safe_browsing/common/BUILD.gn index 4e32332..212b21df 100644 --- a/components/safe_browsing/common/BUILD.gn +++ b/components/safe_browsing/common/BUILD.gn
@@ -20,3 +20,28 @@ "//url/ipc:url_ipc", ] } + +static_library("safe_browsing_prefs") { + sources = [ + "safe_browsing_prefs.cc", + "safe_browsing_prefs.h", + ] + deps = [ + "//base:base", + "//components/prefs", + ] +} + +source_set("unit_tests") { + testonly = true + sources = [ + "safe_browsing_prefs_unittest.cc", + ] + deps = [ + ":safe_browsing_prefs", + "//base:base", + "//base/test:test_support", + "//components/prefs:test_support", + "//testing/gtest", + ] +}
diff --git a/components/safe_browsing/common/DEPS b/components/safe_browsing/common/DEPS index acf92ab..61eff427 100644 --- a/components/safe_browsing/common/DEPS +++ b/components/safe_browsing/common/DEPS
@@ -1,4 +1,5 @@ include_rules = [ + "+components/prefs", "+ipc", "+url" ]
diff --git a/components/safe_browsing_db/safe_browsing_prefs.cc b/components/safe_browsing/common/safe_browsing_prefs.cc similarity index 99% rename from components/safe_browsing_db/safe_browsing_prefs.cc rename to components/safe_browsing/common/safe_browsing_prefs.cc index 3895131c..83f7588 100644 --- a/components/safe_browsing_db/safe_browsing_prefs.cc +++ b/components/safe_browsing/common/safe_browsing_prefs.cc
@@ -2,11 +2,12 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +#include "components/safe_browsing/common/safe_browsing_prefs.h" + #include "base/command_line.h" #include "base/logging.h" #include "base/metrics/histogram_macros.h" #include "components/prefs/pref_service.h" -#include "components/safe_browsing_db/safe_browsing_prefs.h" namespace {
diff --git a/components/safe_browsing_db/safe_browsing_prefs.h b/components/safe_browsing/common/safe_browsing_prefs.h similarity index 96% rename from components/safe_browsing_db/safe_browsing_prefs.h rename to components/safe_browsing/common/safe_browsing_prefs.h index 54666f3..ec87b39 100644 --- a/components/safe_browsing_db/safe_browsing_prefs.h +++ b/components/safe_browsing/common/safe_browsing_prefs.h
@@ -4,8 +4,8 @@ // // Safe Browsing preferences and some basic utility functions for using them. -#ifndef COMPONENTS_SAFE_BROWSING_DB_SAFE_BROWSING_PREFS_H_ -#define COMPONENTS_SAFE_BROWSING_DB_SAFE_BROWSING_PREFS_H_ +#ifndef COMPONENTS_SAFE_BROWSING_COMMON_SAFE_BROWSING_PREFS_H_ +#define COMPONENTS_SAFE_BROWSING_COMMON_SAFE_BROWSING_PREFS_H_ #include "base/feature_list.h" @@ -148,4 +148,4 @@ } // namespace safe_browsing -#endif // COMPONENTS_SAFE_BROWSING_DB_SAFE_BROWSING_PREFS_H_ +#endif // COMPONENTS_SAFE_BROWSING_COMMON_SAFE_BROWSING_PREFS_H_
diff --git a/components/safe_browsing_db/safe_browsing_prefs_unittest.cc b/components/safe_browsing/common/safe_browsing_prefs_unittest.cc similarity index 99% rename from components/safe_browsing_db/safe_browsing_prefs_unittest.cc rename to components/safe_browsing/common/safe_browsing_prefs_unittest.cc index b6b3a08..5d11011 100644 --- a/components/safe_browsing_db/safe_browsing_prefs_unittest.cc +++ b/components/safe_browsing/common/safe_browsing_prefs_unittest.cc
@@ -11,7 +11,7 @@ #include "base/test/scoped_feature_list.h" #include "components/prefs/pref_registry_simple.h" #include "components/prefs/testing_pref_service.h" -#include "components/safe_browsing_db/safe_browsing_prefs.h" +#include "components/safe_browsing/common/safe_browsing_prefs.h" #include "testing/gtest/include/gtest/gtest.h" namespace safe_browsing {
diff --git a/components/safe_browsing_db/BUILD.gn b/components/safe_browsing_db/BUILD.gn index 68a841c..fb9286f 100644 --- a/components/safe_browsing_db/BUILD.gn +++ b/components/safe_browsing_db/BUILD.gn
@@ -31,9 +31,9 @@ ":database_manager", ":hit_report", ":prefix_set", - ":safe_browsing_prefs", ":safebrowsing_proto", ":util", + "//components/safe_browsing/common:safe_browsing_prefs", ] } @@ -82,8 +82,8 @@ ":util", ] deps = [ - ":safe_browsing_prefs", "//components/metrics", + "//components/safe_browsing/common:safe_browsing_prefs", "//url", ] } @@ -152,17 +152,6 @@ ] } -static_library("safe_browsing_prefs") { - sources = [ - "safe_browsing_prefs.cc", - "safe_browsing_prefs.h", - ] - deps = [ - "//base:base", - "//components/prefs", - ] -} - static_library("test_database_manager") { sources = [ "test_database_manager.cc", @@ -181,8 +170,8 @@ "util.h", ] public_deps = [ - ":safe_browsing_prefs", ":v4_protocol_manager_util", + "//components/safe_browsing/common:safe_browsing_prefs", ] deps = [ "//base", @@ -325,12 +314,12 @@ "v4_update_protocol_manager.h", ] deps = [ - ":safe_browsing_prefs", ":safebrowsing_proto", ":util", ":v4_protocol_manager_util", "//base", "//components/data_use_measurement/core", + "//components/safe_browsing/common:safe_browsing_prefs", "//net", "//url", ] @@ -413,7 +402,6 @@ sources = [ "database_manager_unittest.cc", "prefix_set_unittest.cc", - "safe_browsing_prefs_unittest.cc", "util_unittest.cc", "v4_database_unittest.cc", "v4_get_hash_protocol_manager_unittest.cc", @@ -426,7 +414,6 @@ deps = [ ":database_manager", ":prefix_set", - ":safe_browsing_prefs", ":safebrowsing_proto", ":test_database_manager", ":util", @@ -441,6 +428,7 @@ ":v4_update_protocol_manager", "//base", "//components/prefs:test_support", + "//components/safe_browsing/common:safe_browsing_prefs", "//content/test:test_support", "//crypto", "//net",
diff --git a/components/safe_browsing_db/DEPS b/components/safe_browsing_db/DEPS index 7fafc80..55dc17a 100644 --- a/components/safe_browsing_db/DEPS +++ b/components/safe_browsing_db/DEPS
@@ -1,6 +1,6 @@ include_rules = [ "+components/data_use_measurement/core", - "+components/prefs", + "+components/safe_browsing/common/safe_browsing_prefs.h", "+components/variations", "+components/version_info", "+content/public/browser",
diff --git a/components/safe_browsing_db/hit_report.h b/components/safe_browsing_db/hit_report.h index afa5676..4fecc44c 100644 --- a/components/safe_browsing_db/hit_report.h +++ b/components/safe_browsing_db/hit_report.h
@@ -7,7 +7,7 @@ #ifndef COMPONENTS_SAFE_BROWSING_DB_HIT_REPORT_H_ #define COMPONENTS_SAFE_BROWSING_DB_HIT_REPORT_H_ -#include "components/safe_browsing_db/safe_browsing_prefs.h" +#include "components/safe_browsing/common/safe_browsing_prefs.h" #include "components/safe_browsing_db/util.h" #include "url/gurl.h"
diff --git a/components/safe_browsing_db/util.h b/components/safe_browsing_db/util.h index ad6f4e82..dd03f5f 100644 --- a/components/safe_browsing_db/util.h +++ b/components/safe_browsing_db/util.h
@@ -16,7 +16,7 @@ #include "base/strings/string_piece.h" #include "base/time/time.h" -#include "components/safe_browsing_db/safe_browsing_prefs.h" +#include "components/safe_browsing/common/safe_browsing_prefs.h" #include "components/safe_browsing_db/v4_protocol_manager_util.h" class GURL;
diff --git a/components/safe_browsing_db/v4_update_protocol_manager.h b/components/safe_browsing_db/v4_update_protocol_manager.h index 4405742..5c60a0c3 100644 --- a/components/safe_browsing_db/v4_update_protocol_manager.h +++ b/components/safe_browsing_db/v4_update_protocol_manager.h
@@ -21,7 +21,7 @@ #include "base/threading/non_thread_safe.h" #include "base/time/time.h" #include "base/timer/timer.h" -#include "components/safe_browsing_db/safe_browsing_prefs.h" +#include "components/safe_browsing/common/safe_browsing_prefs.h" #include "components/safe_browsing_db/safebrowsing.pb.h" #include "components/safe_browsing_db/util.h" #include "components/safe_browsing_db/v4_protocol_manager_util.h"
diff --git a/components/security_interstitials/content/BUILD.gn b/components/security_interstitials/content/BUILD.gn index d2252c27..d3e598a 100644 --- a/components/security_interstitials/content/BUILD.gn +++ b/components/security_interstitials/content/BUILD.gn
@@ -20,8 +20,8 @@ "//base", "//components/prefs:prefs", "//components/resources", + "//components/safe_browsing/common:safe_browsing_prefs", "//components/safe_browsing_db:hit_report", - "//components/safe_browsing_db:safe_browsing_prefs", "//components/safe_browsing_db:util", "//components/security_interstitials/core:core", "//content/public/browser",
diff --git a/components/security_interstitials/content/DEPS b/components/security_interstitials/content/DEPS index 5cb2f21e..ec5cfcd 100644 --- a/components/security_interstitials/content/DEPS +++ b/components/security_interstitials/content/DEPS
@@ -1,6 +1,7 @@ include_rules = [ "+components/grit/components_resources.h", "+components/prefs", + "+components/safe_browsing/common", "+components/safe_browsing_db", "+components/security_interstitials/core", "+content/public/browser",
diff --git a/components/security_interstitials/content/security_interstitial_controller_client.cc b/components/security_interstitials/content/security_interstitial_controller_client.cc index a40f0d43..87d0789 100644 --- a/components/security_interstitials/content/security_interstitial_controller_client.cc +++ b/components/security_interstitials/content/security_interstitial_controller_client.cc
@@ -7,7 +7,7 @@ #include <utility> #include "components/prefs/pref_service.h" -#include "components/safe_browsing_db/safe_browsing_prefs.h" +#include "components/safe_browsing/common/safe_browsing_prefs.h" #include "components/security_interstitials/core/metrics_helper.h" #include "content/public/browser/interstitial_page.h" #include "content/public/browser/web_contents.h"
diff --git a/components/security_interstitials/content/security_interstitial_page.cc b/components/security_interstitials/content/security_interstitial_page.cc index 3b64147..0e339db6 100644 --- a/components/security_interstitials/content/security_interstitial_page.cc +++ b/components/security_interstitials/content/security_interstitial_page.cc
@@ -11,7 +11,7 @@ #include "base/values.h" #include "components/grit/components_resources.h" #include "components/prefs/pref_service.h" -#include "components/safe_browsing_db/safe_browsing_prefs.h" +#include "components/safe_browsing/common/safe_browsing_prefs.h" #include "components/security_interstitials/content/security_interstitial_controller_client.h" #include "components/security_interstitials/core/common_string_util.h" #include "content/public/browser/interstitial_page.h"
diff --git a/components/subresource_filter/content/browser/content_subresource_filter_driver_factory.cc b/components/subresource_filter/content/browser/content_subresource_filter_driver_factory.cc index c6052e11..45b15bdc 100644 --- a/components/subresource_filter/content/browser/content_subresource_filter_driver_factory.cc +++ b/components/subresource_filter/content/browser/content_subresource_filter_driver_factory.cc
@@ -9,6 +9,8 @@ #include "base/metrics/histogram_macros.h" #include "base/rand_util.h" #include "base/time/time.h" +#include "base/trace_event/trace_event.h" +#include "base/trace_event/trace_event_argument.h" #include "components/subresource_filter/content/browser/content_activation_list_utils.h" #include "components/subresource_filter/content/browser/subresource_filter_client.h" #include "components/subresource_filter/core/browser/subresource_filter_features.h" @@ -119,8 +121,17 @@ url, config.activation_conditions); }); - if (highest_priority_activated_config == - config_list->configs_by_decreasing_priority().end()) { + bool has_activated_config = + highest_priority_activated_config != + config_list->configs_by_decreasing_priority().end(); + TRACE_EVENT1(TRACE_DISABLED_BY_DEFAULT("loading"), + "ContentSubresourceFilterDriverFactory::" + "ComputeActivationForMainFrameNavigation", + "highest_priority_activated_config", + has_activated_config + ? highest_priority_activated_config->ToTracedValue() + : base::MakeUnique<base::trace_event::TracedValue>()); + if (!has_activated_config) { activation_decision_ = ActivationDecision::ACTIVATION_CONDITIONS_NOT_MET; activation_options_ = Configuration::ActivationOptions(); return; @@ -205,6 +216,7 @@ // Only reset the activation decision reason if we would have activated. if (whitelisted && activation_decision_ == ActivationDecision::ACTIVATED) { + TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("loading"), "ActivationWhitelisted"); activation_decision_ = ActivationDecision::URL_WHITELISTED; activation_options_ = Configuration::ActivationOptions(); }
diff --git a/components/subresource_filter/core/browser/subresource_filter_features.cc b/components/subresource_filter/core/browser/subresource_filter_features.cc index 5ce505d..5c2d755f1 100644 --- a/components/subresource_filter/core/browser/subresource_filter_features.cc +++ b/components/subresource_filter/core/browser/subresource_filter_features.cc
@@ -11,14 +11,14 @@ #include <tuple> #include <utility> -#include "base/json/json_writer.h" #include "base/lazy_instance.h" +#include "base/memory/ptr_util.h" #include "base/metrics/field_trial_params.h" #include "base/strings/string_number_conversions.h" #include "base/strings/string_split.h" #include "base/strings/string_util.h" #include "base/synchronization/lock.h" -#include "base/values.h" +#include "base/trace_event/trace_event_argument.h" #include "components/variations/variations_associated_data.h" namespace subresource_filter { @@ -319,27 +319,25 @@ return !(*this == rhs); } -std::ostream& operator<<(std::ostream& os, const Configuration& config) { - base::DictionaryValue dict; - dict.SetString("activation_scope", - StreamToString(config.activation_conditions.activation_scope)); - dict.SetString("activation_list", - StreamToString(config.activation_conditions.activation_list)); - dict.SetInteger("priority", config.activation_conditions.priority); - dict.SetString("activation_level", - StreamToString(config.activation_options.activation_level)); - dict.SetDouble("performance_measurement_rate", - config.activation_options.performance_measurement_rate); - dict.SetBoolean("should_suppress_notifications", - config.activation_options.should_suppress_notifications); - dict.SetBoolean("should_whitelist_site_on_reload", - config.activation_options.should_whitelist_site_on_reload); - dict.SetString("ruleset_flavor", - StreamToString(config.general_settings.ruleset_flavor)); - std::string json; - base::JSONWriter::WriteWithOptions( - dict, base::JSONWriter::OPTIONS_PRETTY_PRINT, &json); - return os << json; +std::unique_ptr<base::trace_event::TracedValue> Configuration::ToTracedValue() + const { + auto value = base::MakeUnique<base::trace_event::TracedValue>(); + value->SetString("activation_scope", + StreamToString(activation_conditions.activation_scope)); + value->SetString("activation_list", + StreamToString(activation_conditions.activation_list)); + value->SetInteger("priority", activation_conditions.priority); + value->SetString("activation_level", + StreamToString(activation_options.activation_level)); + value->SetDouble("performance_measurement_rate", + activation_options.performance_measurement_rate); + value->SetBoolean("should_suppress_notifications", + activation_options.should_suppress_notifications); + value->SetBoolean("should_whitelist_site_on_reload", + activation_options.should_whitelist_site_on_reload); + value->SetString("ruleset_flavor", + StreamToString(general_settings.ruleset_flavor)); + return value; } // ConfigurationList ----------------------------------------------------------
diff --git a/components/subresource_filter/core/browser/subresource_filter_features.h b/components/subresource_filter/core/browser/subresource_filter_features.h index e075356..a828a4e 100644 --- a/components/subresource_filter/core/browser/subresource_filter_features.h +++ b/components/subresource_filter/core/browser/subresource_filter_features.h
@@ -5,7 +5,7 @@ #ifndef COMPONENTS_SUBRESOURCE_FILTER_CORE_BROWSER_SUBRESOURCE_FILTER_FEATURES_H_ #define COMPONENTS_SUBRESOURCE_FILTER_CORE_BROWSER_SUBRESOURCE_FILTER_FEATURES_H_ -#include <iosfwd> +#include <memory> #include <vector> #include "base/feature_list.h" @@ -16,6 +16,12 @@ #include "components/subresource_filter/core/common/activation_list.h" #include "components/subresource_filter/core/common/activation_scope.h" +namespace base { +namespace trace_event { +class TracedValue; +} // namespace trace_event +} // namespace base + namespace subresource_filter { // Encapsulates a set of parameters that define how the subresource filter @@ -102,6 +108,8 @@ bool operator==(const Configuration& rhs) const; bool operator!=(const Configuration& rhs) const; + std::unique_ptr<base::trace_event::TracedValue> ToTracedValue() const; + // Factory methods for preset configurations. // // To add a new preset: @@ -117,9 +125,6 @@ GeneralSettings general_settings; }; -// For logging in tests. -std::ostream& operator<<(std::ostream& os, const Configuration& config); - // Thread-safe, ref-counted wrapper around an immutable list of configurations. class ConfigurationList : public base::RefCountedThreadSafe<ConfigurationList> { public:
diff --git a/components/subresource_filter/core/browser/subresource_filter_features_test_support.cc b/components/subresource_filter/core/browser/subresource_filter_features_test_support.cc index df18a73..dcd7c31 100644 --- a/components/subresource_filter/core/browser/subresource_filter_features_test_support.cc +++ b/components/subresource_filter/core/browser/subresource_filter_features_test_support.cc
@@ -4,11 +4,15 @@ #include "components/subresource_filter/core/browser/subresource_filter_features_test_support.h" +#include <ostream> #include <utility> +#include "base/json/json_writer.h" #include "base/memory/ptr_util.h" #include "base/memory/ref_counted.h" #include "base/strings/string_util.h" +#include "base/trace_event/trace_event_argument.h" +#include "base/values.h" namespace subresource_filter { namespace testing { @@ -83,5 +87,15 @@ ScopedSubresourceFilterFeatureToggle::~ScopedSubresourceFilterFeatureToggle() {} +std::ostream& operator<<(std::ostream& os, const Configuration& config) { + std::unique_ptr<base::Value> value = config.ToTracedValue()->ToBaseValue(); + base::DictionaryValue* dict; + value->GetAsDictionary(&dict); + std::string json; + base::JSONWriter::WriteWithOptions( + *dict, base::JSONWriter::OPTIONS_PRETTY_PRINT, &json); + return os << json; +} + } // namespace testing } // namespace subresource_filter
diff --git a/components/subresource_filter/core/browser/subresource_filter_features_test_support.h b/components/subresource_filter/core/browser/subresource_filter_features_test_support.h index 974e97b..91ad516 100644 --- a/components/subresource_filter/core/browser/subresource_filter_features_test_support.h +++ b/components/subresource_filter/core/browser/subresource_filter_features_test_support.h
@@ -5,6 +5,7 @@ #ifndef COMPONENTS_SUBRESOURCE_FILTER_CORE_BROWSER_SUBRESOURCE_FILTER_FEATURES_TEST_SUPPORT_H_ #define COMPONENTS_SUBRESOURCE_FILTER_CORE_BROWSER_SUBRESOURCE_FILTER_FEATURES_TEST_SUPPORT_H_ +#include <iosfwd> #include <memory> #include <string> @@ -69,6 +70,9 @@ DISALLOW_COPY_AND_ASSIGN(ScopedSubresourceFilterFeatureToggle); }; +// For logging in tests. +std::ostream& operator<<(std::ostream& os, const Configuration& config); + } // namespace testing } // namespace subresource_filter
diff --git a/content/browser/frame_host/render_widget_host_view_child_frame.cc b/content/browser/frame_host/render_widget_host_view_child_frame.cc index 5fdd44e..d5500ab4 100644 --- a/content/browser/frame_host/render_widget_host_view_child_frame.cc +++ b/content/browser/frame_host/render_widget_host_view_child_frame.cc
@@ -475,8 +475,9 @@ } void RenderWidgetHostViewChildFrame::ProcessKeyboardEvent( - const NativeWebKeyboardEvent& event) { - host_->ForwardKeyboardEvent(event); + const NativeWebKeyboardEvent& event, + const ui::LatencyInfo& latency) { + host_->ForwardKeyboardEventWithLatencyInfo(event, latency); } void RenderWidgetHostViewChildFrame::ProcessMouseEvent( @@ -488,7 +489,11 @@ void RenderWidgetHostViewChildFrame::ProcessMouseWheelEvent( const blink::WebMouseWheelEvent& event, const ui::LatencyInfo& latency) { - if (event.delta_x != 0 || event.delta_y != 0) + if (event.delta_x != 0 || event.delta_y != 0 || + event.phase == blink::WebMouseWheelEvent::kPhaseEnded || + event.phase == blink::WebMouseWheelEvent::kPhaseCancelled || + event.momentum_phase == blink::WebMouseWheelEvent::kPhaseEnded || + event.momentum_phase == blink::WebMouseWheelEvent::kPhaseCancelled) host_->ForwardWheelEventWithLatencyInfo(event, latency); }
diff --git a/content/browser/frame_host/render_widget_host_view_child_frame.h b/content/browser/frame_host/render_widget_host_view_child_frame.h index 213581d2..df99f2de 100644 --- a/content/browser/frame_host/render_widget_host_view_child_frame.h +++ b/content/browser/frame_host/render_widget_host_view_child_frame.h
@@ -123,7 +123,8 @@ bool LockMouse() override; void UnlockMouse() override; cc::FrameSinkId GetFrameSinkId() override; - void ProcessKeyboardEvent(const NativeWebKeyboardEvent& event) override; + void ProcessKeyboardEvent(const NativeWebKeyboardEvent& event, + const ui::LatencyInfo& latency) override; void ProcessMouseEvent(const blink::WebMouseEvent& event, const ui::LatencyInfo& latency) override; void ProcessMouseWheelEvent(const blink::WebMouseWheelEvent& event,
diff --git a/content/browser/indexed_db/leveldb/leveldb_database.cc b/content/browser/indexed_db/leveldb/leveldb_database.cc index f157f5e..ca777c7 100644 --- a/content/browser/indexed_db/leveldb/leveldb_database.cc +++ b/content/browser/indexed_db/leveldb/leveldb_database.cc
@@ -481,6 +481,14 @@ "leveldb/index_db/0x%" PRIXPTR, reinterpret_cast<uintptr_t>(db_.get()))); dump->AddScalar(base::trace_event::MemoryAllocatorDump::kNameSize, base::trace_event::MemoryAllocatorDump::kUnitsBytes, size); + + // Dumps in BACKGROUND mode cannot have strings or edges in order to minimize + // trace size and instrumentation overhead. + if (args.level_of_detail == + base::trace_event::MemoryDumpLevelOfDetail::BACKGROUND) { + return true; + } + dump->AddString("file_name", "", file_name_for_tracing); // Memory is allocated from system allocator (malloc).
diff --git a/content/browser/loader/navigation_url_loader_network_service.cc b/content/browser/loader/navigation_url_loader_network_service.cc index 5ea32da..ccb4290 100644 --- a/content/browser/loader/navigation_url_loader_network_service.cc +++ b/content/browser/loader/navigation_url_loader_network_service.cc
@@ -18,6 +18,11 @@ #include "content/browser/loader/navigation_resource_handler.h" #include "content/browser/loader/navigation_resource_throttle.h" #include "content/browser/loader/navigation_url_loader_delegate.h" +#include "content/browser/resource_context_impl.h" +#include "content/browser/service_worker/service_worker_navigation_handle.h" +#include "content/browser/service_worker/service_worker_navigation_handle_core.h" +#include "content/browser/service_worker/service_worker_request_handler.h" +#include "content/browser/web_contents/web_contents_impl.h" #include "content/browser/webui/url_data_manager_backend.h" #include "content/browser/webui/web_ui_url_loader_factory.h" #include "content/public/browser/browser_thread.h" @@ -39,37 +44,103 @@ namespace { static base::LazyInstance<mojom::URLLoaderFactoryPtr>::Leaky - g_url_loader_factory = LAZY_INSTANCE_INITIALIZER; + g_url_loader_factory; +#if DCHECK_IS_ON() +static bool g_url_loader_factory_retrieved; +#endif // DCHECK_IS_ON() -using CompleteNavigationStartCallback = - base::Callback<void(mojom::URLLoaderFactoryPtrInfo, - std::unique_ptr<ResourceRequest>)>; +WebContents* GetWebContentsFromFrameTreeNodeID(int frame_tree_node_id) { + DCHECK_CURRENTLY_ON(BrowserThread::UI); + FrameTreeNode* frame_tree_node = + FrameTreeNode::GloballyFindByID(frame_tree_node_id); + if (!frame_tree_node) + return nullptr; -void PrepareNavigationOnIOThread( + return WebContentsImpl::FromFrameTreeNode(frame_tree_node); +} + +void PrepareNavigationStartOnIO( std::unique_ptr<ResourceRequest> resource_request, ResourceContext* resource_context, - ResourceType resource_type, + ServiceWorkerNavigationHandleCore* service_worker_navigation_handle_core, AppCacheNavigationHandleCore* appcache_handle_core, - CompleteNavigationStartCallback complete_request) { - if (resource_request->request_body.get()) { + NavigationRequestInfo* request_info, + mojom::URLLoaderFactoryPtrInfo factory_from_ui, + const base::Callback<WebContents*(void)>& web_contents_getter, + mojom::URLLoaderAssociatedRequest url_loader_request, + mojom::URLLoaderClientPtr url_loader_client_to_pass, + std::unique_ptr<service_manager::Connector> connector) { + DCHECK_CURRENTLY_ON(BrowserThread::IO); + + const ResourceType resource_type = request_info->is_main_frame + ? RESOURCE_TYPE_MAIN_FRAME + : RESOURCE_TYPE_SUB_FRAME; + + if (resource_request->request_body) { AttachRequestBodyBlobDataHandles(resource_request->request_body.get(), resource_context); } - mojom::URLLoaderFactoryPtrInfo url_loader_factory_ptr_info; + mojom::URLLoaderFactoryPtr url_loader_factory_ptr; + if (service_worker_navigation_handle_core) { + RequestContextFrameType frame_type = + request_info->is_main_frame ? REQUEST_CONTEXT_FRAME_TYPE_TOP_LEVEL + : REQUEST_CONTEXT_FRAME_TYPE_NESTED; - if (appcache_handle_core) { + storage::BlobStorageContext* blob_storage_context = GetBlobStorageContext( + GetChromeBlobStorageContextForResourceContext(resource_context)); + url_loader_factory_ptr = + ServiceWorkerRequestHandler::InitializeForNavigationNetworkService( + *resource_request, resource_context, + service_worker_navigation_handle_core, blob_storage_context, + request_info->begin_params.skip_service_worker, resource_type, + request_info->begin_params.request_context_type, frame_type, + request_info->are_ancestors_secure, + request_info->common_params.post_data, web_contents_getter); + } + + // TODO(scottmg): We need to rework AppCache to have it return a + // URLLoaderFactoryPtr[Info] here. We should also try to have it return + // synchronously in as many cases as possible (especially when there's no + // AppCache) to simplify and speed the common case. + if (false /*appcache_handle_core*/) { AppCacheRequestHandler::InitializeForNavigationNetworkService( std::move(resource_request), resource_context, appcache_handle_core, - resource_type, complete_request); + resource_type, + base::Callback<void( + mojom::URLLoaderFactoryPtrInfo, + std::unique_ptr<ResourceRequest>)>() /* TODO(ananta) */); return; } - BrowserThread::PostTask( - BrowserThread::UI, FROM_HERE, - base::Bind(complete_request, - base::Passed(std::move(url_loader_factory_ptr_info)), - base::Passed(std::move(resource_request)))); + // If we haven't gotten one from the above, then use the one the UI thread + // gave us, or otherwise fallback to the default. + mojom::URLLoaderFactory* factory; + if (url_loader_factory_ptr) { + factory = url_loader_factory_ptr.get(); + } else { + if (factory_from_ui.is_valid()) { + url_loader_factory_ptr.Bind(std::move(factory_from_ui)); + factory = url_loader_factory_ptr.get(); + } else { + if (!g_url_loader_factory.Get()) { +#if DCHECK_IS_ON() + DCHECK(!g_url_loader_factory_retrieved); +#endif // DCHECK_IS_ON() + connector->BindInterface(mojom::kNetworkServiceName, + &g_url_loader_factory.Get()); +#if DCHECK_IS_ON() + g_url_loader_factory_retrieved = true; +#endif // DCHECK_IS_ON() + } + factory = g_url_loader_factory.Get().get(); + } + } + + factory->CreateLoaderAndStart( + std::move(url_loader_request), 0 /* routing_id? */, 0 /* request_id? */, + mojom::kURLLoadOptionSendSSLInfo, *resource_request, + std::move(url_loader_client_to_pass)); } } // namespace @@ -79,13 +150,12 @@ StoragePartition* storage_partition, std::unique_ptr<NavigationRequestInfo> request_info, std::unique_ptr<NavigationUIData> navigation_ui_data, - ServiceWorkerNavigationHandle* service_worker_handle, + ServiceWorkerNavigationHandle* service_worker_navigation_handle, AppCacheNavigationHandle* appcache_handle, NavigationURLLoaderDelegate* delegate) : delegate_(delegate), binding_(this), - request_info_(std::move(request_info)), - weak_factory_(this) { + request_info_(std::move(request_info)) { DCHECK_CURRENTLY_ON(BrowserThread::UI); TRACE_EVENT_ASYNC_BEGIN_WITH_TIMESTAMP1( @@ -123,24 +193,38 @@ new_request->request_body = request_info_->common_params.post_data.get(); - // AppCache or post data needs some handling on the IO thread. - // The request body may need blob handles to be added to it. This - // functionality has to be invoked on the IO thread. - if (/*appcache_handle || */ new_request->request_body.get()) { - ResourceType resource_type = request_info_->is_main_frame - ? RESOURCE_TYPE_MAIN_FRAME - : RESOURCE_TYPE_SUB_FRAME; - BrowserThread::PostTask( - BrowserThread::IO, FROM_HERE, - base::Bind( - &PrepareNavigationOnIOThread, base::Passed(std::move(new_request)), - resource_context, resource_type, - appcache_handle ? appcache_handle->core() : nullptr, - base::Bind(&NavigationURLLoaderNetworkService::StartURLRequest, - weak_factory_.GetWeakPtr()))); - return; + mojom::URLLoaderAssociatedRequest loader_associated_request = + mojo::MakeRequest(&url_loader_associated_ptr_); + mojom::URLLoaderClientPtr url_loader_client_ptr_to_pass; + binding_.Bind(mojo::MakeRequest(&url_loader_client_ptr_to_pass)); + + // Check if a web UI scheme wants to handle this request. + mojom::URLLoaderFactoryPtrInfo factory_ptr_info; + + const auto& schemes = URLDataManagerBackend::GetWebUISchemes(); + if (std::find(schemes.begin(), schemes.end(), new_request->url.scheme()) != + schemes.end()) { + FrameTreeNode* frame_tree_node = + FrameTreeNode::GloballyFindByID(request_info_->frame_tree_node_id); + factory_ptr_info = GetWebUIURLLoader(frame_tree_node).PassInterface(); } - StartURLRequest(mojom::URLLoaderFactoryPtrInfo(), std::move(new_request)); + + BrowserThread::PostTask( + BrowserThread::IO, FROM_HERE, + base::Bind(&PrepareNavigationStartOnIO, + base::Passed(std::move(new_request)), resource_context, + service_worker_navigation_handle + ? service_worker_navigation_handle->core() + : nullptr, + appcache_handle ? appcache_handle->core() : nullptr, + request_info_.get(), base::Passed(std::move(factory_ptr_info)), + base::Bind(&GetWebContentsFromFrameTreeNodeID, + request_info_->frame_tree_node_id), + base::Passed(std::move(loader_associated_request)), + base::Passed(std::move(url_loader_client_ptr_to_pass)), + base::Passed(ServiceManagerConnection::GetForProcess() + ->GetConnector() + ->Clone()))); } NavigationURLLoaderNetworkService::~NavigationURLLoaderNetworkService() {} @@ -222,63 +306,4 @@ } } -void NavigationURLLoaderNetworkService::StartURLRequest( - mojom::URLLoaderFactoryPtrInfo url_loader_factory_info, - std::unique_ptr<ResourceRequest> request) { - DCHECK_CURRENTLY_ON(BrowserThread::UI); - - // Bind the URLClient implementation to this object to pass to the URLLoader. - if (binding_.is_bound()) - binding_.Unbind(); - - mojom::URLLoaderClientPtr url_loader_client_ptr_to_pass; - binding_.Bind(mojo::MakeRequest(&url_loader_client_ptr_to_pass)); - - mojom::URLLoaderFactory* factory = nullptr; - // This |factory_ptr| will be destroyed when it goes out of scope. Because - // |url_loader_associated_ptr_| is associated with it, it will be disconnected - // as well. That means NavigationURLLoaderNetworkService::FollowRedirect() - // won't work as expected, the |url_loader_associated_ptr_| will silently drop - // calls. - // This is fine for now since the only user of this is WebUI which doesn't - // need this, but we'll have to fix this when other consumers come up. - mojom::URLLoaderFactoryPtr factory_ptr; - const auto& schemes = URLDataManagerBackend::GetWebUISchemes(); - if (std::find(schemes.begin(), schemes.end(), request->url.scheme()) != - schemes.end()) { - FrameTreeNode* frame_tree_node = - FrameTreeNode::GloballyFindByID(request_info_->frame_tree_node_id); - factory_ptr = GetWebUIURLLoader(frame_tree_node); - factory = factory_ptr.get(); - } - - if (!factory) { - // If a URLLoaderFactory was provided, then we use that one, otherwise - // fall back to connecting directly to the network service. - if (url_loader_factory_info.is_valid()) { - url_loader_factory_.Bind(std::move(url_loader_factory_info)); - factory = url_loader_factory_.get(); - } else { - factory = GetURLLoaderFactory(); - } - } - - factory->CreateLoaderAndStart(mojo::MakeRequest(&url_loader_associated_ptr_), - 0 /* routing_id? */, 0 /* request_id? */, - mojom::kURLLoadOptionSendSSLInfo, *request, - std::move(url_loader_client_ptr_to_pass)); -} - -mojom::URLLoaderFactory* -NavigationURLLoaderNetworkService::GetURLLoaderFactory() { - // TODO(yzshen): We will need the ability to customize the factory per frame - // e.g., for appcache or service worker. - if (!g_url_loader_factory.Get()) { - ServiceManagerConnection::GetForProcess()->GetConnector()->BindInterface( - mojom::kNetworkServiceName, &g_url_loader_factory.Get()); - } - - return g_url_loader_factory.Get().get(); -} - } // namespace content
diff --git a/content/browser/loader/navigation_url_loader_network_service.h b/content/browser/loader/navigation_url_loader_network_service.h index b5700e1..50ff253 100644 --- a/content/browser/loader/navigation_url_loader_network_service.h +++ b/content/browser/loader/navigation_url_loader_network_service.h
@@ -6,7 +6,6 @@ #define CONTENT_BROWSER_LOADER_NAVIGATION_URL_LOADER_NETWORK_SERVICE_H_ #include "base/macros.h" -#include "base/memory/weak_ptr.h" #include "content/browser/loader/navigation_url_loader.h" #include "content/common/content_export.h" #include "content/common/url_loader.mojom.h" @@ -66,27 +65,15 @@ void OnComplete( const ResourceRequestCompletionStatus& completion_status) override; - // Initiates the request. - void StartURLRequest(mojom::URLLoaderFactoryPtrInfo url_loader_factory_info, - std::unique_ptr<ResourceRequest> request); - private: - void ConnectURLLoaderFactory( - std::unique_ptr<service_manager::Connector> connector); - - mojom::URLLoaderFactory* GetURLLoaderFactory(); - NavigationURLLoaderDelegate* delegate_; - mojom::URLLoaderFactoryPtr url_loader_factory_; mojo::Binding<mojom::URLLoaderClient> binding_; std::unique_ptr<NavigationRequestInfo> request_info_; mojom::URLLoaderAssociatedPtr url_loader_associated_ptr_; scoped_refptr<ResourceResponse> response_; SSLStatus ssl_status_; - base::WeakPtrFactory<NavigationURLLoaderNetworkService> weak_factory_; - DISALLOW_COPY_AND_ASSIGN(NavigationURLLoaderNetworkService); };
diff --git a/content/browser/memory/memory_condition_observer.cc b/content/browser/memory/memory_condition_observer.cc index 0891302d..075beab4 100644 --- a/content/browser/memory/memory_condition_observer.cc +++ b/content/browser/memory/memory_condition_observer.cc
@@ -13,7 +13,7 @@ namespace { -// A expected renderer size. These values come from the median of appropriate +// An expected renderer size. These values come from the median of appropriate // UMA stats. #if defined(OS_ANDROID) || defined(OS_IOS) const int kDefaultExpectedRendererSizeMB = 40; @@ -31,7 +31,7 @@ const int kDefaultMonitoringIntervalSeconds = 1; const int kMonitoringIntervalBackgroundedSeconds = 120; -void SetIntVariationParameter(const std::map<std::string, std::string> params, +void SetIntVariationParameter(const std::map<std::string, std::string>& params, const char* name, int* target) { const auto& iter = params.find(name); @@ -45,7 +45,7 @@ } void SetSecondsVariationParameter( - const std::map<std::string, std::string> params, + const std::map<std::string, std::string>& params, const char* name, base::TimeDelta* target) { const auto& iter = params.find(name);
diff --git a/content/browser/renderer_host/input/render_widget_host_latency_tracker.cc b/content/browser/renderer_host/input/render_widget_host_latency_tracker.cc index 2e07058..26f0c1e 100644 --- a/content/browser/renderer_host/input/render_widget_host_latency_tracker.cc +++ b/content/browser/renderer_host/input/render_widget_host_latency_tracker.cc
@@ -31,7 +31,9 @@ if (type == blink::WebInputEvent::kMouseWheel) { return "Wheel"; } else if (WebInputEvent::IsKeyboardEventType(type)) { - return "Key"; + // We should only be reporting latency for key presses. + DCHECK(type == WebInputEvent::kRawKeyDown || type == WebInputEvent::kChar); + return "KeyPress"; } else if (WebInputEvent::IsMouseEventType(type)) { return "Mouse"; } else if (WebInputEvent::IsTouchEventType(type)) { @@ -102,8 +104,8 @@ if (latency.coalesced()) return; - if (type != blink::WebInputEvent::kMouseWheel && - !WebInputEvent::IsTouchEventType(type)) { + if (latency.source_event_type() == ui::SourceEventType::UNKNOWN || + latency.source_event_type() == ui::SourceEventType::OTHER) { return; } @@ -124,24 +126,33 @@ base::TimeDelta ui_delta = rwh_component.last_event_time - ui_component.first_event_time; - if (type == blink::WebInputEvent::kMouseWheel) { + if (latency.source_event_type() == ui::SourceEventType::WHEEL) { UMA_HISTOGRAM_CUSTOM_COUNTS("Event.Latency.Browser.WheelUI", ui_delta.InMicroseconds(), 1, 20000, 100); - } else { - DCHECK(WebInputEvent::IsTouchEventType(type)); + } else if (latency.source_event_type() == ui::SourceEventType::TOUCH) { UMA_HISTOGRAM_CUSTOM_COUNTS("Event.Latency.Browser.TouchUI", ui_delta.InMicroseconds(), 1, 20000, 100); + } else if (latency.source_event_type() == ui::SourceEventType::KEY_PRESS) { + UMA_HISTOGRAM_CUSTOM_COUNTS("Event.Latency.Browser.KeyPressUI", + ui_delta.InMicroseconds(), 1, 20000, 50); + } else { + // We should only report these histograms for wheel, touch and keyboard. + NOTREACHED(); } } - // Both tap and scroll gestures depend on the disposition of the touch start - // and the current touch. For touch start, touch_start_default_prevented_ == - // (ack_result == INPUT_EVENT_ACK_STATE_CONSUMED). + // Touchscreen tap and scroll gestures depend on the disposition of the touch + // start and the current touch. For touch start, + // touch_start_default_prevented_ == (ack_result == + // INPUT_EVENT_ACK_STATE_CONSUMED). bool action_prevented = touch_start_default_prevented_ || ack_result == INPUT_EVENT_ACK_STATE_CONSUMED; std::string event_name = WebInputEvent::GetName(type); + if (latency.source_event_type() == ui::KEY_PRESS) + event_name = "KeyPress"; + std::string default_action_status = action_prevented ? "DefaultPrevented" : "DefaultAllowed"; @@ -188,6 +199,11 @@ active_multi_finger_gesture_ = touch_event.touches_length != 1; } + if (latency->source_event_type() == ui::KEY_PRESS) { + DCHECK(event.GetType() == WebInputEvent::kChar || + event.GetType() == WebInputEvent::kRawKeyDown); + } + if (latency->FindLatency(ui::INPUT_EVENT_LATENCY_BEGIN_RWH_COMPONENT, latency_component_id_, NULL)) { return;
diff --git a/content/browser/renderer_host/input/render_widget_host_latency_tracker_unittest.cc b/content/browser/renderer_host/input/render_widget_host_latency_tracker_unittest.cc index 827441a..7655c4c9 100644 --- a/content/browser/renderer_host/input/render_widget_host_latency_tracker_unittest.cc +++ b/content/browser/renderer_host/input/render_widget_host_latency_tracker_unittest.cc
@@ -589,6 +589,7 @@ auto wheel = SyntheticWebMouseWheelEventBuilder::Build( blink::WebMouseWheelEvent::kPhaseChanged); ui::LatencyInfo wheel_latency; + wheel_latency.set_source_event_type(ui::SourceEventType::WHEEL); AddFakeComponents(*tracker(), &wheel_latency); tracker()->OnInputEvent(wheel, &wheel_latency); tracker()->OnInputEventAck(wheel, &wheel_latency, @@ -602,6 +603,7 @@ SyntheticWebTouchEvent touch; touch.PressPoint(0, 0); ui::LatencyInfo touch_latency; + touch_latency.set_source_event_type(ui::SourceEventType::TOUCH); AddFakeComponents(*tracker(), &touch_latency); tracker()->OnInputEvent(touch, &touch_latency); tracker()->OnInputEventAck(touch, &touch_latency, @@ -629,6 +631,7 @@ auto key_event = SyntheticWebKeyboardEventBuilder::Build(blink::WebKeyboardEvent::kChar); ui::LatencyInfo key_latency; + key_latency.set_source_event_type(ui::SourceEventType::KEY_PRESS); AddFakeComponents(*tracker(), &key_latency); tracker()->OnInputEvent(key_event, &key_latency); tracker()->OnInputEventAck(key_event, &key_latency, @@ -725,9 +728,11 @@ event.PressPoint(1, 1); ui::LatencyInfo latency; + latency.set_source_event_type(ui::SourceEventType::TOUCH); tracker()->OnInputEvent(event, &latency); ui::LatencyInfo fake_latency; + fake_latency.set_source_event_type(ui::SourceEventType::TOUCH); fake_latency.AddLatencyNumberWithTimestamp( ui::INPUT_EVENT_LATENCY_BEGIN_RWH_COMPONENT, tracker()->latency_component_id(), 0, @@ -760,6 +765,7 @@ { // Touch move. ui::LatencyInfo latency; + latency.set_source_event_type(ui::SourceEventType::TOUCH); event.MovePoint(0, 20, 20); tracker()->OnInputEvent(event, &latency); @@ -772,6 +778,7 @@ EXPECT_EQ(2U, latency.latency_components().size()); ui::LatencyInfo fake_latency; + fake_latency.set_source_event_type(ui::SourceEventType::TOUCH); fake_latency.AddLatencyNumberWithTimestamp( ui::INPUT_EVENT_LATENCY_BEGIN_RWH_COMPONENT, tracker()->latency_component_id(), 0, @@ -801,6 +808,7 @@ { // Touch end. ui::LatencyInfo latency; + latency.set_source_event_type(ui::SourceEventType::TOUCH); event.ReleasePoint(0); tracker()->OnInputEvent(event, &latency); @@ -813,6 +821,7 @@ EXPECT_EQ(2U, latency.latency_components().size()); ui::LatencyInfo fake_latency; + fake_latency.set_source_event_type(ui::SourceEventType::TOUCH); fake_latency.AddLatencyNumberWithTimestamp( ui::INPUT_EVENT_LATENCY_BEGIN_RWH_COMPONENT, tracker()->latency_component_id(), 0, @@ -899,6 +908,178 @@ touchend_timestamps_ms[2] - touchend_timestamps_ms[1], 1))); } +TEST_F(RenderWidgetHostLatencyTrackerTest, KeyBlockingAndQueueingTime) { + // These numbers are sensitive to where the histogram buckets are. + int event_timestamps_ms[] = {11, 25, 35}; + + for (InputEventAckState blocking : + {INPUT_EVENT_ACK_STATE_NOT_CONSUMED, INPUT_EVENT_ACK_STATE_CONSUMED}) { + { + NativeWebKeyboardEvent event(blink::WebKeyboardEvent::kRawKeyDown, + blink::WebInputEvent::kNoModifiers, + base::TimeTicks::Now()); + ui::LatencyInfo latency_info; + latency_info.set_source_event_type(ui::SourceEventType::KEY_PRESS); + tracker()->OnInputEvent(event, &latency_info); + + ui::LatencyInfo fake_latency; + fake_latency.set_source_event_type(ui::SourceEventType::KEY_PRESS); + fake_latency.AddLatencyNumberWithTimestamp( + ui::INPUT_EVENT_LATENCY_BEGIN_RWH_COMPONENT, + tracker()->latency_component_id(), 0, + base::TimeTicks() + + base::TimeDelta::FromMilliseconds(event_timestamps_ms[0]), + 1); + + fake_latency.AddLatencyNumberWithTimestamp( + ui::INPUT_EVENT_LATENCY_RENDERER_MAIN_COMPONENT, 0, 0, + base::TimeTicks() + + base::TimeDelta::FromMilliseconds(event_timestamps_ms[1]), + 1); + + fake_latency.AddLatencyNumberWithTimestamp( + ui::INPUT_EVENT_LATENCY_ACK_RWH_COMPONENT, 0, 0, + base::TimeTicks() + + base::TimeDelta::FromMilliseconds(event_timestamps_ms[2]), + 1); + + // Call ComputeInputLatencyHistograms directly to avoid OnInputEventAck + // overwriting components. + tracker()->ComputeInputLatencyHistograms( + event.GetType(), tracker()->latency_component_id(), fake_latency, + blocking); + + tracker()->OnInputEventAck(event, &latency_info, blocking); + } + } + + EXPECT_THAT( + histogram_tester().GetAllSamples( + "Event.Latency.QueueingTime.KeyPressDefaultPrevented"), + ElementsAre(Bucket(event_timestamps_ms[1] - event_timestamps_ms[0], 1))); + EXPECT_THAT( + histogram_tester().GetAllSamples( + "Event.Latency.QueueingTime.KeyPressDefaultAllowed"), + ElementsAre(Bucket(event_timestamps_ms[1] - event_timestamps_ms[0], 1))); + EXPECT_THAT( + histogram_tester().GetAllSamples( + "Event.Latency.BlockingTime.KeyPressDefaultPrevented"), + ElementsAre(Bucket(event_timestamps_ms[2] - event_timestamps_ms[1], 1))); + EXPECT_THAT( + histogram_tester().GetAllSamples( + "Event.Latency.BlockingTime.KeyPressDefaultAllowed"), + ElementsAre(Bucket(event_timestamps_ms[2] - event_timestamps_ms[1], 1))); +} + +TEST_F(RenderWidgetHostLatencyTrackerTest, KeyUILatency) { + // These numbers are sensitive to where the histogram buckets are. + int event_timestamps_microseconds[] = {100, 185}; + + NativeWebKeyboardEvent event(blink::WebKeyboardEvent::kChar, + blink::WebInputEvent::kNoModifiers, + base::TimeTicks::Now()); + ui::LatencyInfo latency_info; + latency_info.set_source_event_type(ui::SourceEventType::KEY_PRESS); + latency_info.AddLatencyNumberWithTimestamp( + ui::INPUT_EVENT_LATENCY_UI_COMPONENT, 0, 0, + base::TimeTicks() + + base::TimeDelta::FromMicroseconds(event_timestamps_microseconds[0]), + 1); + + latency_info.AddLatencyNumberWithTimestamp( + ui::INPUT_EVENT_LATENCY_BEGIN_RWH_COMPONENT, + tracker()->latency_component_id(), 0, + base::TimeTicks() + + base::TimeDelta::FromMicroseconds(event_timestamps_microseconds[1]), + 1); + + tracker()->OnInputEvent(event, &latency_info); + tracker()->OnInputEventAck(event, &latency_info, + InputEventAckState::INPUT_EVENT_ACK_STATE_UNKNOWN); + EXPECT_THAT( + histogram_tester().GetAllSamples("Event.Latency.Browser.KeyPressUI"), + ElementsAre(Bucket( + event_timestamps_microseconds[1] - event_timestamps_microseconds[0], + 1))); +} + +TEST_F(RenderWidgetHostLatencyTrackerTest, KeyAckedLatency) { + // These numbers are sensitive to where the histogram buckets are. + int event_timestamps_microseconds[] = {11, 24}; + + NativeWebKeyboardEvent event(blink::WebKeyboardEvent::kRawKeyDown, + blink::WebInputEvent::kNoModifiers, + base::TimeTicks::Now()); + ui::LatencyInfo latency_info; + latency_info.set_source_event_type(ui::SourceEventType::KEY_PRESS); + + latency_info.AddLatencyNumberWithTimestamp( + ui::INPUT_EVENT_LATENCY_BEGIN_RWH_COMPONENT, + tracker()->latency_component_id(), 0, + base::TimeTicks() + + base::TimeDelta::FromMicroseconds(event_timestamps_microseconds[0]), + 1); + + latency_info.AddLatencyNumberWithTimestamp( + ui::INPUT_EVENT_LATENCY_ACK_RWH_COMPONENT, 0, 0, + base::TimeTicks() + + base::TimeDelta::FromMicroseconds(event_timestamps_microseconds[1]), + 1); + + tracker()->OnInputEvent(event, &latency_info); + // Call ComputeInputLatencyHistograms directly to avoid OnInputEventAck + // overwriting components. + tracker()->ComputeInputLatencyHistograms( + event.GetType(), tracker()->latency_component_id(), latency_info, + InputEventAckState::INPUT_EVENT_ACK_STATE_UNKNOWN); + + EXPECT_THAT( + histogram_tester().GetAllSamples("Event.Latency.Browser.KeyPressAcked"), + ElementsAre(Bucket( + event_timestamps_microseconds[1] - event_timestamps_microseconds[0], + 1))); +} + +TEST_F(RenderWidgetHostLatencyTrackerTest, KeyEndToEndLatency) { + // These numbers are sensitive to where the histogram buckets are. + int event_timestamps_microseconds[] = {11, 24}; + + ui::LatencyInfo latency_info; + latency_info.set_source_event_type(ui::SourceEventType::KEY_PRESS); + latency_info.AddLatencyNumberWithTimestamp( + ui::INPUT_EVENT_LATENCY_ORIGINAL_COMPONENT, 0, 0, + base::TimeTicks() + + base::TimeDelta::FromMicroseconds(event_timestamps_microseconds[0]), + 1); + + latency_info.AddLatencyNumberWithTimestamp( + ui::INPUT_EVENT_LATENCY_BEGIN_RWH_COMPONENT, + tracker()->latency_component_id(), 0, + base::TimeTicks() + + base::TimeDelta::FromMicroseconds(event_timestamps_microseconds[0]), + 1); + + latency_info.AddLatencyNumberWithTimestamp( + ui::INPUT_EVENT_GPU_SWAP_BUFFER_COMPONENT, 0, 0, + base::TimeTicks() + + base::TimeDelta::FromMicroseconds(event_timestamps_microseconds[1]), + 1); + + latency_info.AddLatencyNumberWithTimestamp( + ui::INPUT_EVENT_LATENCY_TERMINATED_FRAME_SWAP_COMPONENT, 0, 0, + base::TimeTicks() + + base::TimeDelta::FromMicroseconds(event_timestamps_microseconds[1]), + 1); + + tracker()->OnGpuSwapBuffersCompleted(latency_info); + + EXPECT_THAT( + histogram_tester().GetAllSamples("Event.Latency.EndToEnd.KeyPress"), + ElementsAre(Bucket( + event_timestamps_microseconds[1] - event_timestamps_microseconds[0], + 1))); +} + // Event.Latency.(Queueing|Blocking)Time.* histograms shouldn't be reported for // multi-finger touch. TEST_F(RenderWidgetHostLatencyTrackerTest, @@ -966,6 +1147,7 @@ { // First touch start. ui::LatencyInfo latency; + latency.set_source_event_type(ui::SourceEventType::TOUCH); touch_event.PressPoint(1, 1); tracker()->OnInputEvent(touch_event, &latency); tracker()->OnInputEventAck(touch_event, &latency, ack_state); @@ -974,6 +1156,7 @@ { // Second touch start. ui::LatencyInfo latency; + latency.set_source_event_type(ui::SourceEventType::TOUCH); touch_event.PressPoint(1, 1); tracker()->OnInputEvent(touch_event, &latency); tracker()->OnInputEventAck(touch_event, &latency, ack_state); @@ -982,6 +1165,7 @@ { // Wheel event. ui::LatencyInfo latency; + latency.set_source_event_type(ui::SourceEventType::WHEEL); // These numbers are sensitive to where the histogram buckets are. int timestamps_ms[] = {11, 25, 35}; auto wheel_event = SyntheticWebMouseWheelEventBuilder::Build( @@ -989,6 +1173,7 @@ tracker()->OnInputEvent(touch_event, &latency); ui::LatencyInfo fake_latency; + fake_latency.set_source_event_type(ui::SourceEventType::TOUCH); fake_latency.AddLatencyNumberWithTimestamp( ui::INPUT_EVENT_LATENCY_BEGIN_RWH_COMPONENT, tracker()->latency_component_id(), 0,
diff --git a/content/browser/renderer_host/input/synthetic_gesture_target_aura.cc b/content/browser/renderer_host/input/synthetic_gesture_target_aura.cc index 9538287..08f560fa 100644 --- a/content/browser/renderer_host/input/synthetic_gesture_target_aura.cc +++ b/content/browser/renderer_host/input/synthetic_gesture_target_aura.cc
@@ -12,6 +12,7 @@ #include "content/browser/renderer_host/render_widget_host_impl.h" #include "content/browser/renderer_host/render_widget_host_view_aura.h" #include "content/browser/renderer_host/ui_events_helper.h" +#include "ui/aura/event_injector.h" #include "ui/aura/window.h" #include "ui/aura/window_tree_host.h" #include "ui/events/event_sink.h" @@ -46,9 +47,10 @@ aura::Window* window = GetWindow(); aura::WindowTreeHost* host = window->GetHost(); + aura::EventInjector injector; + for (const auto& event : events) { event->ConvertLocationToTarget(window, host->window()); - // Apply the screen scale factor to the event location after it has been // transformed to the target. gfx::PointF device_location = @@ -57,8 +59,7 @@ gfx::ScalePoint(event->root_location_f(), device_scale_factor_); event->set_location_f(device_location); event->set_root_location_f(device_root_location); - ui::EventDispatchDetails details = - host->event_sink()->OnEventFromSource(event.get()); + ui::EventDispatchDetails details = injector.Inject(host, event.get()); if (details.dispatcher_destroyed) break; } @@ -77,8 +78,9 @@ aura::Window* window = GetWindow(); wheel_event.ConvertLocationToTarget(window, window->GetRootWindow()); + aura::EventInjector injector; ui::EventDispatchDetails details = - window->GetHost()->event_sink()->OnEventFromSource(&wheel_event); + injector.Inject(window->GetHost(), &wheel_event); if (details.dispatcher_destroyed) return; } @@ -162,8 +164,9 @@ aura::Window* window = GetWindow(); mouse_event.ConvertLocationToTarget(window, window->GetRootWindow()); + aura::EventInjector injector; ui::EventDispatchDetails details = - window->GetHost()->event_sink()->OnEventFromSource(&mouse_event); + injector.Inject(window->GetHost(), &mouse_event); if (details.dispatcher_destroyed) return; }
diff --git a/content/browser/renderer_host/render_widget_host_impl.cc b/content/browser/renderer_host/render_widget_host_impl.cc index dbc1a4d..c036914 100644 --- a/content/browser/renderer_host/render_widget_host_impl.cc +++ b/content/browser/renderer_host/render_widget_host_impl.cc
@@ -1045,8 +1045,8 @@ } void RenderWidgetHostImpl::ForwardMouseEventWithLatencyInfo( - const blink::WebMouseEvent& mouse_event, - const ui::LatencyInfo& ui_latency) { + const blink::WebMouseEvent& mouse_event, + const ui::LatencyInfo& latency) { TRACE_EVENT2("input", "RenderWidgetHostImpl::ForwardMouseEvent", "x", mouse_event.PositionInWidget().x, "y", mouse_event.PositionInWidget().y); @@ -1062,7 +1062,7 @@ if (touch_emulator_ && touch_emulator_->HandleMouseEvent(mouse_event)) return; - MouseEventWithLatencyInfo mouse_with_latency(mouse_event, ui_latency); + MouseEventWithLatencyInfo mouse_with_latency(mouse_event, latency); DispatchInputEventWithLatencyInfo(mouse_event, &mouse_with_latency.latency); input_router_->SendMouseEvent(mouse_with_latency); } @@ -1074,8 +1074,8 @@ } void RenderWidgetHostImpl::ForwardWheelEventWithLatencyInfo( - const blink::WebMouseWheelEvent& wheel_event, - const ui::LatencyInfo& ui_latency) { + const blink::WebMouseWheelEvent& wheel_event, + const ui::LatencyInfo& latency) { TRACE_EVENT2("input", "RenderWidgetHostImpl::ForwardWheelEvent", "dx", wheel_event.delta_x, "dy", wheel_event.delta_y); @@ -1085,7 +1085,7 @@ if (touch_emulator_ && touch_emulator_->HandleMouseWheelEvent(wheel_event)) return; - MouseWheelEventWithLatencyInfo wheel_with_latency(wheel_event, ui_latency); + MouseWheelEventWithLatencyInfo wheel_with_latency(wheel_event, latency); DispatchInputEventWithLatencyInfo(wheel_event, &wheel_with_latency.latency); input_router_->SendWheelEvent(wheel_with_latency); } @@ -1105,7 +1105,7 @@ void RenderWidgetHostImpl::ForwardGestureEventWithLatencyInfo( const blink::WebGestureEvent& gesture_event, - const ui::LatencyInfo& ui_latency) { + const ui::LatencyInfo& latency) { TRACE_EVENT0("input", "RenderWidgetHostImpl::ForwardGestureEvent"); // Early out if necessary, prior to performing latency logic. if (ShouldDropInputEvents()) @@ -1156,7 +1156,7 @@ if (delegate_->PreHandleGestureEvent(gesture_event)) return; - GestureEventWithLatencyInfo gesture_with_latency(gesture_event, ui_latency); + GestureEventWithLatencyInfo gesture_with_latency(gesture_event, latency); DispatchInputEventWithLatencyInfo(gesture_event, &gesture_with_latency.latency); input_router_->SendGestureEvent(gesture_with_latency); @@ -1179,14 +1179,14 @@ } void RenderWidgetHostImpl::ForwardTouchEventWithLatencyInfo( - const blink::WebTouchEvent& touch_event, - const ui::LatencyInfo& ui_latency) { + const blink::WebTouchEvent& touch_event, + const ui::LatencyInfo& latency) { TRACE_EVENT0("input", "RenderWidgetHostImpl::ForwardTouchEvent"); // Always forward TouchEvents for touch stream consistency. They will be // ignored if appropriate in FilterInputEvent(). - TouchEventWithLatencyInfo touch_with_latency(touch_event, ui_latency); + TouchEventWithLatencyInfo touch_with_latency(touch_event, latency); if (touch_emulator_ && touch_emulator_->HandleTouchEvent(touch_with_latency.event)) { if (view_) { @@ -1202,11 +1202,24 @@ void RenderWidgetHostImpl::ForwardKeyboardEvent( const NativeWebKeyboardEvent& key_event) { - ForwardKeyboardEventWithCommands(key_event, nullptr, nullptr); + ui::LatencyInfo latency_info; + + if (key_event.GetType() == WebInputEvent::kRawKeyDown || + key_event.GetType() == WebInputEvent::kChar) { + latency_info.set_source_event_type(ui::SourceEventType::KEY_PRESS); + } + ForwardKeyboardEventWithLatencyInfo(key_event, latency_info); +} + +void RenderWidgetHostImpl::ForwardKeyboardEventWithLatencyInfo( + const NativeWebKeyboardEvent& key_event, + const ui::LatencyInfo& latency) { + ForwardKeyboardEventWithCommands(key_event, latency, nullptr, nullptr); } void RenderWidgetHostImpl::ForwardKeyboardEventWithCommands( const NativeWebKeyboardEvent& key_event, + const ui::LatencyInfo& latency, const std::vector<EditCommand>* commands, bool* update_event) { TRACE_EVENT0("input", "RenderWidgetHostImpl::ForwardKeyboardEvent"); @@ -1283,9 +1296,8 @@ if (touch_emulator_ && touch_emulator_->HandleKeyboardEvent(key_event)) return; - ui::LatencyInfo latency_info(ui::SourceEventType::OTHER); NativeWebKeyboardEventWithLatencyInfo key_event_with_latency(key_event, - latency_info); + latency); key_event_with_latency.event.is_browser_shortcut = is_shortcut; DispatchInputEventWithLatencyInfo(key_event, &key_event_with_latency.latency); // TODO(foolip): |InputRouter::SendKeyboardEvent()| may filter events, in
diff --git a/content/browser/renderer_host/render_widget_host_impl.h b/content/browser/renderer_host/render_widget_host_impl.h index a9807e79..0a5c0db 100644 --- a/content/browser/renderer_host/render_widget_host_impl.h +++ b/content/browser/renderer_host/render_widget_host_impl.h
@@ -345,23 +345,26 @@ // aura. void ForwardKeyboardEventWithCommands( const NativeWebKeyboardEvent& key_event, + const ui::LatencyInfo& latency, const std::vector<EditCommand>* commands, bool* update_event = nullptr); // Forwards the given message to the renderer. These are called by the view // when it has received a message. + void ForwardKeyboardEventWithLatencyInfo( + const NativeWebKeyboardEvent& key_event, + const ui::LatencyInfo& latency) override; void ForwardGestureEventWithLatencyInfo( const blink::WebGestureEvent& gesture_event, - const ui::LatencyInfo& ui_latency) override; + const ui::LatencyInfo& latency) override; virtual void ForwardTouchEventWithLatencyInfo( const blink::WebTouchEvent& touch_event, - const ui::LatencyInfo& ui_latency); // Virtual for testing. - void ForwardMouseEventWithLatencyInfo( - const blink::WebMouseEvent& mouse_event, - const ui::LatencyInfo& ui_latency); + const ui::LatencyInfo& latency); // Virtual for testing. + void ForwardMouseEventWithLatencyInfo(const blink::WebMouseEvent& mouse_event, + const ui::LatencyInfo& latency); virtual void ForwardWheelEventWithLatencyInfo( const blink::WebMouseWheelEvent& wheel_event, - const ui::LatencyInfo& ui_latency); // Virtual for testing. + const ui::LatencyInfo& latency); // Virtual for testing. // Enables/disables touch emulation using mouse event. See TouchEmulator. void SetTouchEventEmulationEnabled(
diff --git a/content/browser/renderer_host/render_widget_host_unittest.cc b/content/browser/renderer_host/render_widget_host_unittest.cc index 0e3f32db..5760996 100644 --- a/content/browser/renderer_host/render_widget_host_unittest.cc +++ b/content/browser/renderer_host/render_widget_host_unittest.cc
@@ -639,7 +639,8 @@ GetNextSimulatedEventTimeSeconds()); EditCommands commands; commands.emplace_back("name", "value"); - host_->ForwardKeyboardEventWithCommands(native_event, &commands, nullptr); + host_->ForwardKeyboardEventWithCommands(native_event, ui::LatencyInfo(), + &commands, nullptr); } void SimulateMouseEvent(WebInputEvent::Type type) {
diff --git a/content/browser/renderer_host/render_widget_host_view_android.cc b/content/browser/renderer_host/render_widget_host_view_android.cc index 57c17da..ae875fc 100644 --- a/content/browser/renderer_host/render_widget_host_view_android.cc +++ b/content/browser/renderer_host/render_widget_host_view_android.cc
@@ -1754,7 +1754,13 @@ if (!target_host) return; - target_host->ForwardKeyboardEvent(event); + ui::LatencyInfo latency_info; + if (event.GetType() == blink::WebInputEvent::kRawKeyDown || + event.GetType() == blink::WebInputEvent::kChar) { + latency_info.set_source_event_type(ui::SourceEventType::KEY_PRESS); + } + latency_info.AddLatencyNumber(ui::INPUT_EVENT_LATENCY_UI_COMPONENT, 0, 0); + target_host->ForwardKeyboardEventWithLatencyInfo(event, latency_info); } void RenderWidgetHostViewAndroid::SendMouseEvent(
diff --git a/content/browser/renderer_host/render_widget_host_view_aura.cc b/content/browser/renderer_host/render_widget_host_view_aura.cc index c3defe30..cdc4c14b 100644 --- a/content/browser/renderer_host/render_widget_host_view_aura.cc +++ b/content/browser/renderer_host/render_widget_host_view_aura.cc
@@ -1231,8 +1231,9 @@ if (host_ && (event_handler_->accept_return_character() || event.GetCharacter() != ui::VKEY_RETURN)) { // Send a blink::WebInputEvent::Char event to |host_|. - ForwardKeyboardEvent(NativeWebKeyboardEvent(event, event.GetCharacter()), - nullptr); + ForwardKeyboardEventWithLatencyInfo( + NativeWebKeyboardEvent(event, event.GetCharacter()), *event.latency(), + nullptr); } } @@ -2236,8 +2237,9 @@ } } -void RenderWidgetHostViewAura::ForwardKeyboardEvent( +void RenderWidgetHostViewAura::ForwardKeyboardEventWithLatencyInfo( const NativeWebKeyboardEvent& event, + const ui::LatencyInfo& latency, bool* update_event) { RenderWidgetHostImpl* target_host = host_; @@ -2264,13 +2266,14 @@ it->argument())); } - target_host->ForwardKeyboardEventWithCommands(event, &edit_commands, - update_event); + target_host->ForwardKeyboardEventWithCommands(event, latency, + &edit_commands, update_event); return; } #endif - target_host->ForwardKeyboardEventWithCommands(event, nullptr, update_event); + target_host->ForwardKeyboardEventWithCommands(event, latency, nullptr, + update_event); } void RenderWidgetHostViewAura::CreateSelectionController() {
diff --git a/content/browser/renderer_host/render_widget_host_view_aura.h b/content/browser/renderer_host/render_widget_host_view_aura.h index b4a4c994..b0975162 100644 --- a/content/browser/renderer_host/render_widget_host_view_aura.h +++ b/content/browser/renderer_host/render_widget_host_view_aura.h
@@ -313,8 +313,9 @@ // RenderWidgetHostViewEventHandler::Delegate: gfx::Rect ConvertRectToScreen(const gfx::Rect& rect) const override; - void ForwardKeyboardEvent(const NativeWebKeyboardEvent& event, - bool* update_event) override; + void ForwardKeyboardEventWithLatencyInfo(const NativeWebKeyboardEvent& event, + const ui::LatencyInfo& latency, + bool* update_event) override; RenderFrameHostImpl* GetFocusedFrame(); bool NeedsMouseCapture() override; void SetTooltipsEnabled(bool enable) override;
diff --git a/content/browser/renderer_host/render_widget_host_view_base.h b/content/browser/renderer_host/render_widget_host_view_base.h index 6bb3159a..2c2364fc 100644 --- a/content/browser/renderer_host/render_widget_host_view_base.h +++ b/content/browser/renderer_host/render_widget_host_view_base.h
@@ -264,7 +264,8 @@ cc::SurfaceHittestDelegate* delegate, const gfx::Point& point, gfx::Point* transformed_point); - virtual void ProcessKeyboardEvent(const NativeWebKeyboardEvent& event) {} + virtual void ProcessKeyboardEvent(const NativeWebKeyboardEvent& event, + const ui::LatencyInfo& latency) {} virtual void ProcessMouseEvent(const blink::WebMouseEvent& event, const ui::LatencyInfo& latency) {} virtual void ProcessMouseWheelEvent(const blink::WebMouseWheelEvent& event,
diff --git a/content/browser/renderer_host/render_widget_host_view_event_handler.cc b/content/browser/renderer_host/render_widget_host_view_event_handler.cc index 980a6780..bccea9a 100644 --- a/content/browser/renderer_host/render_widget_host_view_event_handler.cc +++ b/content/browser/renderer_host/render_widget_host_view_event_handler.cc
@@ -284,7 +284,8 @@ SetKeyboardFocus(); // We don't have to communicate with an input method here. NativeWebKeyboardEvent webkit_event(*event); - delegate_->ForwardKeyboardEvent(webkit_event, &mark_event_as_handled); + delegate_->ForwardKeyboardEventWithLatencyInfo( + webkit_event, *event->latency(), &mark_event_as_handled); } if (mark_event_as_handled) event->SetHandled();
diff --git a/content/browser/renderer_host/render_widget_host_view_event_handler.h b/content/browser/renderer_host/render_widget_host_view_event_handler.h index 8f80ee7..acf53312 100644 --- a/content/browser/renderer_host/render_widget_host_view_event_handler.h +++ b/content/browser/renderer_host/render_widget_host_view_event_handler.h
@@ -62,8 +62,10 @@ // to the renderer instead. |update_event| (if non-null) is set to indicate // whether ui::KeyEvent::SetHandled() should be called on the underlying // ui::KeyEvent. - virtual void ForwardKeyboardEvent(const NativeWebKeyboardEvent& event, - bool* update_event) = 0; + virtual void ForwardKeyboardEventWithLatencyInfo( + const NativeWebKeyboardEvent& event, + const ui::LatencyInfo& latency, + bool* update_event) = 0; // Returns whether the widget needs to grab mouse capture to work properly. virtual bool NeedsMouseCapture() = 0; virtual void SetTooltipsEnabled(bool enable) = 0;
diff --git a/content/browser/renderer_host/render_widget_host_view_mac.mm b/content/browser/renderer_host/render_widget_host_view_mac.mm index e9ff56d..8394c80 100644 --- a/content/browser/renderer_host/render_widget_host_view_mac.mm +++ b/content/browser/renderer_host/render_widget_host_view_mac.mm
@@ -2110,6 +2110,13 @@ DCHECK(widgetHost); NativeWebKeyboardEvent event(theEvent); + ui::LatencyInfo latency_info; + if (event.GetType() == blink::WebInputEvent::kRawKeyDown || + event.GetType() == blink::WebInputEvent::kChar) { + latency_info.set_source_event_type(ui::SourceEventType::KEY_PRESS); + } + + latency_info.AddLatencyNumber(ui::INPUT_EVENT_LATENCY_UI_COMPONENT, 0, 0); // Force fullscreen windows to close on Escape so they won't keep the keyboard // grabbed or be stuck onscreen if the renderer is hanging. @@ -2149,7 +2156,7 @@ // We only handle key down events and just simply forward other events. if ([theEvent type] != NSKeyDown) { - widgetHost->ForwardKeyboardEvent(event); + widgetHost->ForwardKeyboardEventWithLatencyInfo(event, latency_info); // Possibly autohide the cursor. if ([self shouldAutohideCursorForEvent:theEvent]) @@ -2204,7 +2211,7 @@ NativeWebKeyboardEvent fakeEvent = event; fakeEvent.windows_key_code = 0xE5; // VKEY_PROCESSKEY fakeEvent.skip_in_browser = true; - widgetHost->ForwardKeyboardEvent(fakeEvent); + widgetHost->ForwardKeyboardEventWithLatencyInfo(fakeEvent, latency_info); // If this key event was handled by the input method, but // -doCommandBySelector: (invoked by the call to -interpretKeyEvents: above) // enqueued edit commands, then in order to let webkit handle them @@ -2215,12 +2222,14 @@ if (hasEditCommands_ && !hasMarkedText_) delayEventUntilAfterImeCompostion = YES; } else { - widgetHost->ForwardKeyboardEventWithCommands(event, &editCommands_); + widgetHost->ForwardKeyboardEventWithCommands(event, latency_info, + &editCommands_); } - // Calling ForwardKeyboardEvent() could have destroyed the widget. When the - // widget was destroyed, |renderWidgetHostView_->render_widget_host_| will - // be set to NULL. So we check it here and return immediately if it's NULL. + // Calling ForwardKeyboardEventWithCommands() could have destroyed the + // widget. When the widget was destroyed, + // |renderWidgetHostView_->render_widget_host_| will be set to NULL. So we + // check it here and return immediately if it's NULL. if (!renderWidgetHostView_->render_widget_host_) return; @@ -2279,16 +2288,18 @@ NativeWebKeyboardEvent fakeEvent = event; fakeEvent.SetType(blink::WebInputEvent::kKeyUp); fakeEvent.skip_in_browser = true; - widgetHost->ForwardKeyboardEvent(fakeEvent); + widgetHost->ForwardKeyboardEventWithLatencyInfo(fakeEvent, latency_info); // Not checking |renderWidgetHostView_->render_widget_host_| here because // a key event with |skip_in_browser| == true won't be handled by browser, // thus it won't destroy the widget. - widgetHost->ForwardKeyboardEventWithCommands(event, &editCommands_); + widgetHost->ForwardKeyboardEventWithCommands(event, latency_info, + &editCommands_); - // Calling ForwardKeyboardEvent() could have destroyed the widget. When the - // widget was destroyed, |renderWidgetHostView_->render_widget_host_| will - // be set to NULL. So we check it here and return immediately if it's NULL. + // Calling ForwardKeyboardEventWithCommands() could have destroyed the + // widget. When the widget was destroyed, + // |renderWidgetHostView_->render_widget_host_| will be set to NULL. So we + // check it here and return immediately if it's NULL. if (!renderWidgetHostView_->render_widget_host_) return; } @@ -2303,7 +2314,7 @@ event.text[0] = textToBeInserted_[0]; event.text[1] = 0; event.skip_in_browser = true; - widgetHost->ForwardKeyboardEvent(event); + widgetHost->ForwardKeyboardEventWithLatencyInfo(event, latency_info); } else if ((!textInserted || delayEventUntilAfterImeCompostion) && event.text[0] != '\0' && (([theEvent modifierFlags] & kCtrlCmdKeyMask) || @@ -2313,7 +2324,7 @@ // cases, unless the key event generated any other command. event.SetType(blink::WebInputEvent::kChar); event.skip_in_browser = true; - widgetHost->ForwardKeyboardEvent(event); + widgetHost->ForwardKeyboardEventWithLatencyInfo(event, latency_info); } }
diff --git a/content/browser/service_worker/service_worker_request_handler.cc b/content/browser/service_worker/service_worker_request_handler.cc index e23397d4..ac4edb27 100644 --- a/content/browser/service_worker/service_worker_request_handler.cc +++ b/content/browser/service_worker/service_worker_request_handler.cc
@@ -7,6 +7,7 @@ #include <string> #include <utility> +#include "base/command_line.h" #include "base/macros.h" #include "content/browser/service_worker/service_worker_context_core.h" #include "content/browser/service_worker/service_worker_context_wrapper.h" @@ -20,6 +21,7 @@ #include "content/public/browser/resource_context.h" #include "content/public/common/browser_side_navigation_policy.h" #include "content/public/common/child_process_host.h" +#include "content/public/common/content_switches.h" #include "content/public/common/origin_util.h" #include "ipc/ipc_message.h" #include "net/base/url_util.h" @@ -131,6 +133,28 @@ navigation_handle_core->DidPreCreateProviderHost(std::move(provider_host)); } +// PlzNavigate and --enable-network-service. +// static +mojom::URLLoaderFactoryPtr +ServiceWorkerRequestHandler::InitializeForNavigationNetworkService( + const ResourceRequest& resource_request, + ResourceContext* resource_context, + ServiceWorkerNavigationHandleCore* navigation_handle_core, + storage::BlobStorageContext* blob_storage_context, + bool skip_service_worker, + ResourceType resource_type, + RequestContextType request_context_type, + RequestContextFrameType frame_type, + bool is_parent_frame_secure, + scoped_refptr<ResourceRequestBodyImpl> body, + const base::Callback<WebContents*(void)>& web_contents_getter) { + DCHECK(IsBrowserSideNavigationEnabled() && + base::CommandLine::ForCurrentProcess()->HasSwitch( + switches::kEnableNetworkService)); + // TODO(scottmg): Currently being implemented. See https://crbug.com/715640. + return mojom::URLLoaderFactoryPtr(); +} + void ServiceWorkerRequestHandler::InitializeHandler( net::URLRequest* request, ServiceWorkerContextWrapper* context_wrapper,
diff --git a/content/browser/service_worker/service_worker_request_handler.h b/content/browser/service_worker/service_worker_request_handler.h index 61dd8b5..98d24569 100644 --- a/content/browser/service_worker/service_worker_request_handler.h +++ b/content/browser/service_worker/service_worker_request_handler.h
@@ -15,6 +15,7 @@ #include "content/common/content_export.h" #include "content/common/service_worker/service_worker_status_code.h" #include "content/common/service_worker/service_worker_types.h" +#include "content/common/url_loader_factory.mojom.h" #include "content/public/common/request_context_frame_type.h" #include "content/public/common/request_context_type.h" #include "content/public/common/resource_type.h" @@ -60,6 +61,22 @@ scoped_refptr<ResourceRequestBodyImpl> body, const base::Callback<WebContents*(void)>& web_contents_getter); + // PlzNavigate and --enable-network-service. + // Same as InitializeForNavigation() but instead of attaching to a URLRequest, + // returns a URLLoaderFactoryPtrInfo if the request needs to be handled. + static mojom::URLLoaderFactoryPtr InitializeForNavigationNetworkService( + const ResourceRequest& resource_request, + ResourceContext* resource_context, + ServiceWorkerNavigationHandleCore* navigation_handle_core, + storage::BlobStorageContext* blob_storage_context, + bool skip_service_worker, + ResourceType resource_type, + RequestContextType request_context_type, + RequestContextFrameType frame_type, + bool is_parent_frame_secure, + scoped_refptr<ResourceRequestBodyImpl> body, + const base::Callback<WebContents*(void)>& web_contents_getter); + // Attaches a newly created handler if the given |request| needs to // be handled by ServiceWorker. // TODO(kinuko): While utilizing UserData to attach data to URLRequest
diff --git a/content/browser/site_per_process_mac_browsertest.mm b/content/browser/site_per_process_mac_browsertest.mm index 43e5f344..5cae49a 100644 --- a/content/browser/site_per_process_mac_browsertest.mm +++ b/content/browser/site_per_process_mac_browsertest.mm
@@ -58,6 +58,54 @@ DISALLOW_COPY_AND_ASSIGN(TextInputClientMacHelper); }; +// Class to detect incoming gesture event acks for scrolling tests. +class InputEventAckWaiter + : public content::RenderWidgetHost::InputEventObserver { + public: + InputEventAckWaiter(blink::WebInputEvent::Type ack_type_waiting_for) + : message_loop_runner_(new content::MessageLoopRunner), + ack_type_waiting_for_(ack_type_waiting_for), + desired_ack_type_received_(false) {} + ~InputEventAckWaiter() override {} + + void OnInputEventAck(const blink::WebInputEvent& event) override { + if (event.GetType() != ack_type_waiting_for_) + return; + + // Ignore synthetic GestureScrollBegin/Ends. + if ((event.GetType() == blink::WebInputEvent::kGestureScrollBegin && + static_cast<const blink::WebGestureEvent&>(event) + .data.scroll_begin.synthetic) || + (event.GetType() == blink::WebInputEvent::kGestureScrollEnd && + static_cast<const blink::WebGestureEvent&>(event) + .data.scroll_end.synthetic)) { + return; + } + + desired_ack_type_received_ = true; + if (message_loop_runner_->loop_running()) + message_loop_runner_->Quit(); + } + + void Wait() { + if (!desired_ack_type_received_) { + message_loop_runner_->Run(); + } + } + + void Reset() { + desired_ack_type_received_ = false; + message_loop_runner_ = new content::MessageLoopRunner; + } + + private: + scoped_refptr<content::MessageLoopRunner> message_loop_runner_; + blink::WebInputEvent::Type ack_type_waiting_for_; + bool desired_ack_type_received_; + + DISALLOW_COPY_AND_ASSIGN(InputEventAckWaiter); +}; + } // namespace // Site per process browser tests inside content which are specific to Mac OSX @@ -117,4 +165,91 @@ EXPECT_EQ(word, helper.word()); EXPECT_EQ("This", word); } + +// Ensure that the RWHVCF forwards wheel events with phase ending information. +// RWHVCF may see wheel events with phase ending information that have deltas +// of 0. These should not be dropped, otherwise MouseWheelEventQueue will not +// be informed that the user's gesture has ended. +// See crbug.com/628742 +IN_PROC_BROWSER_TEST_F(SitePerProcessMacBrowserTest, + ForwardWheelEventsWithPhaseEndingInformation) { + GURL main_url(embedded_test_server()->GetURL( + "a.com", "/cross_site_iframe_factory.html?a(b)")); + EXPECT_TRUE(NavigateToURL(shell(), main_url)); + + FrameTreeNode* root = static_cast<WebContentsImpl*>(shell()->web_contents()) + ->GetFrameTree() + ->root(); + ASSERT_EQ(1U, root->child_count()); + + FrameTreeNode* child_iframe_node = root->child_at(0); + RenderWidgetHost* child_rwh = + child_iframe_node->current_frame_host()->GetRenderWidgetHost(); + + std::unique_ptr<InputEventAckWaiter> gesture_scroll_begin_ack_observer = + base::MakeUnique<InputEventAckWaiter>( + blink::WebInputEvent::kGestureScrollBegin); + std::unique_ptr<InputEventAckWaiter> gesture_scroll_end_ack_observer = + base::MakeUnique<InputEventAckWaiter>( + blink::WebInputEvent::kGestureScrollEnd); + child_rwh->AddInputEventObserver(gesture_scroll_begin_ack_observer.get()); + child_rwh->AddInputEventObserver(gesture_scroll_end_ack_observer.get()); + + RenderWidgetHostViewBase* child_rwhv = + static_cast<RenderWidgetHostViewBase*>(child_rwh->GetView()); + + blink::WebMouseWheelEvent scroll_event( + blink::WebInputEvent::kMouseWheel, blink::WebInputEvent::kNoModifiers, + blink::WebInputEvent::kTimeStampForTesting); + scroll_event.SetPositionInWidget(1, 1); + scroll_event.has_precise_scrolling_deltas = true; + scroll_event.delta_x = 0.0f; + + // Have the RWHVCF process a sequence of touchpad scroll events that contain + // phase informaiton. We start scrolling normally, then we fling. + // We wait for GestureScrollBegin/Ends that result from these wheel events. + // If we don't see them, this test will time out indicating failure. + + // Begin scrolling. + scroll_event.delta_y = -1.0f; + scroll_event.phase = blink::WebMouseWheelEvent::kPhaseBegan; + scroll_event.momentum_phase = blink::WebMouseWheelEvent::kPhaseNone; + child_rwhv->ProcessMouseWheelEvent(scroll_event, ui::LatencyInfo()); + gesture_scroll_begin_ack_observer->Wait(); + + scroll_event.delta_y = -2.0f; + scroll_event.phase = blink::WebMouseWheelEvent::kPhaseChanged; + scroll_event.momentum_phase = blink::WebMouseWheelEvent::kPhaseNone; + child_rwhv->ProcessMouseWheelEvent(scroll_event, ui::LatencyInfo()); + + // End of non-momentum scrolling. + scroll_event.delta_y = 0.0f; + scroll_event.phase = blink::WebMouseWheelEvent::kPhaseEnded; + scroll_event.momentum_phase = blink::WebMouseWheelEvent::kPhaseNone; + child_rwhv->ProcessMouseWheelEvent(scroll_event, ui::LatencyInfo()); + gesture_scroll_end_ack_observer->Wait(); + + gesture_scroll_begin_ack_observer->Reset(); + gesture_scroll_end_ack_observer->Reset(); + + // We now go into a fling. + scroll_event.delta_y = -2.0f; + scroll_event.phase = blink::WebMouseWheelEvent::kPhaseNone; + scroll_event.momentum_phase = blink::WebMouseWheelEvent::kPhaseBegan; + child_rwhv->ProcessMouseWheelEvent(scroll_event, ui::LatencyInfo()); + gesture_scroll_begin_ack_observer->Wait(); + + scroll_event.delta_y = -2.0f; + scroll_event.phase = blink::WebMouseWheelEvent::kPhaseNone; + scroll_event.momentum_phase = blink::WebMouseWheelEvent::kPhaseChanged; + child_rwhv->ProcessMouseWheelEvent(scroll_event, ui::LatencyInfo()); + + // End of fling momentum. + scroll_event.delta_y = 0.0f; + scroll_event.phase = blink::WebMouseWheelEvent::kPhaseNone; + scroll_event.momentum_phase = blink::WebMouseWheelEvent::kPhaseEnded; + child_rwhv->ProcessMouseWheelEvent(scroll_event, ui::LatencyInfo()); + gesture_scroll_end_ack_observer->Wait(); +} + } // namespace content
diff --git a/content/child/OWNERS b/content/child/OWNERS index a0281e6..40e30002 100644 --- a/content/child/OWNERS +++ b/content/child/OWNERS
@@ -1,5 +1,5 @@ # For Blink API usage -esprehn@chromium.org +dglazkov@chromium.org # For resource loading yhirano@chromium.org
diff --git a/content/public/android/BUILD.gn b/content/public/android/BUILD.gn index 1add51d..b5e6ffe 100644 --- a/content/public/android/BUILD.gn +++ b/content/public/android/BUILD.gn
@@ -112,11 +112,11 @@ "java/src/org/chromium/content/browser/ActivityContentVideoViewEmbedder.java", "java/src/org/chromium/content/browser/AudioFocusDelegate.java", "java/src/org/chromium/content/browser/BackgroundSyncNetworkObserver.java", - "java/src/org/chromium/content/browser/BaseChildProcessConnection.java", "java/src/org/chromium/content/browser/BindingManager.java", "java/src/org/chromium/content/browser/BindingManagerImpl.java", "java/src/org/chromium/content/browser/BrowserStartupController.java", "java/src/org/chromium/content/browser/ChildConnectionAllocator.java", + "java/src/org/chromium/content/browser/ChildProcessConnection.java", "java/src/org/chromium/content/browser/ChildProcessConstants.java", "java/src/org/chromium/content/browser/ChildProcessLauncher.java", "java/src/org/chromium/content/browser/ChildProcessLauncherHelper.java", @@ -133,12 +133,10 @@ "java/src/org/chromium/content/browser/DeviceUtils.java", "java/src/org/chromium/content/browser/FloatingActionModeCallback.java", "java/src/org/chromium/content/browser/GpuProcessCallback.java", - "java/src/org/chromium/content/browser/ImportantChildProcessConnection.java", "java/src/org/chromium/content/browser/InterfaceRegistrarImpl.java", "java/src/org/chromium/content/browser/InterstitialPageDelegateAndroid.java", "java/src/org/chromium/content/browser/JavascriptInterface.java", "java/src/org/chromium/content/browser/LauncherThread.java", - "java/src/org/chromium/content/browser/ManagedChildProcessConnection.java", "java/src/org/chromium/content/browser/MediaResourceGetter.java", "java/src/org/chromium/content/browser/MediaSessionImpl.java", "java/src/org/chromium/content/browser/MemoryMonitorAndroid.java",
diff --git a/content/public/android/java/src/org/chromium/content/browser/BindingManager.java b/content/public/android/java/src/org/chromium/content/browser/BindingManager.java index fdba176..ffa1bb0 100644 --- a/content/public/android/java/src/org/chromium/content/browser/BindingManager.java +++ b/content/public/android/java/src/org/chromium/content/browser/BindingManager.java
@@ -31,7 +31,7 @@ * Registers a freshly started child process. This can be called on any thread. * @param pid handle of the service process */ - void addNewConnection(int pid, ManagedChildProcessConnection connection); + void addNewConnection(int pid, ChildProcessConnection connection); /** * Called when the service visibility changes or is determined for the first time. On low-memory
diff --git a/content/public/android/java/src/org/chromium/content/browser/BindingManagerImpl.java b/content/public/android/java/src/org/chromium/content/browser/BindingManagerImpl.java index 601e96e..05944c8 100644 --- a/content/public/android/java/src/org/chromium/content/browser/BindingManagerImpl.java +++ b/content/public/android/java/src/org/chromium/content/browser/BindingManagerImpl.java
@@ -177,12 +177,12 @@ private ModerateBindingPool mModerateBindingPool; /** - * Wraps ManagedChildProcessConnection keeping track of additional information needed to manage - * the bindings of the connection. It goes away when the connection goes away. + * Wraps ChildProcessConnection keeping track of additional information needed to manage the + * bindings of the connection. It goes away when the connection goes away. */ private class ManagedConnection { // The connection to the service. - private final ManagedChildProcessConnection mConnection; + private final ChildProcessConnection mConnection; // True iff there is a strong binding kept on the service because it is working in // foreground. @@ -234,7 +234,7 @@ * binding. * @param connection The ChildProcessConnection to add to the moderate binding pool. */ - private void addConnectionToModerateBindingPool(ManagedChildProcessConnection connection) { + private void addConnectionToModerateBindingPool(ChildProcessConnection connection) { if (mModerateBindingPool != null && !connection.isStrongBindingBound()) { mModerateBindingPool.addConnection(ManagedConnection.this); } @@ -260,7 +260,7 @@ mConnection.dropOomBindings(); } - ManagedConnection(ManagedChildProcessConnection connection) { + ManagedConnection(ChildProcessConnection connection) { mConnection = connection; } @@ -345,7 +345,7 @@ } @Override - public void addNewConnection(int pid, ManagedChildProcessConnection connection) { + public void addNewConnection(int pid, ChildProcessConnection connection) { assert LauncherThread.runningOnLauncherThread(); // This will reset the previous entry for the pid in the unlikely event of the OS // reusing renderer pids.
diff --git a/content/public/android/java/src/org/chromium/content/browser/ChildConnectionAllocator.java b/content/public/android/java/src/org/chromium/content/browser/ChildConnectionAllocator.java index 18b591b..33a3855 100644 --- a/content/public/android/java/src/org/chromium/content/browser/ChildConnectionAllocator.java +++ b/content/public/android/java/src/org/chromium/content/browser/ChildConnectionAllocator.java
@@ -26,11 +26,26 @@ public class ChildConnectionAllocator { private static final String TAG = "ChildConnAllocator"; - // The factory used to create BaseChildProcessConnection instances. - private final BaseChildProcessConnection.Factory mConnectionFactory; + /** Factory interface. Used by tests to specialize created connections. */ + @VisibleForTesting + protected interface ConnectionFactory { + ChildProcessConnection createConnection(ChildSpawnData spawnData, + ChildProcessConnection.DeathCallback deathCallback, + Bundle childProcessCommonParameters, String serviceClassName); + } + + /** Default implementation of the ConnectionFactory that creates actual connections. */ + private static class ConnectionFactoryImpl implements ConnectionFactory { + public ChildProcessConnection createConnection(ChildSpawnData spawnData, + ChildProcessConnection.DeathCallback deathCallback, + Bundle childProcessCommonParameters, String serviceClassName) { + return new ChildProcessConnection(spawnData.getContext(), deathCallback, + serviceClassName, childProcessCommonParameters, spawnData.getCreationParams()); + } + } // Connections to services. Indices of the array correspond to the service numbers. - private final BaseChildProcessConnection[] mChildProcessConnections; + private final ChildProcessConnection[] mChildProcessConnections; private final String mServiceClassName; @@ -41,12 +56,13 @@ // dequeue the pending spawn data from the same allocator as the connection. private final Queue<ChildSpawnData> mPendingSpawnQueue = new LinkedList<>(); + private ConnectionFactory mConnectionFactory = new ConnectionFactoryImpl(); + /** * Factory method that retrieves the service name and number of service from the * AndroidManifest.xml. */ - public static ChildConnectionAllocator create(Context context, - BaseChildProcessConnection.Factory connectionFactory, String packageName, + public static ChildConnectionAllocator create(Context context, String packageName, String serviceClassNameManifestKey, String numChildServicesManifestKey) { String serviceClassName = null; int numServices = -1; @@ -76,8 +92,7 @@ throw new RuntimeException("Illegal meta data value: the child service doesn't exist"); } - return new ChildConnectionAllocator( - connectionFactory, packageName, serviceClassName, numServices); + return new ChildConnectionAllocator(packageName, serviceClassName, numServices); } // TODO(jcivelli): remove this method once crbug.com/693484 has been addressed. @@ -106,17 +121,14 @@ */ @VisibleForTesting public static ChildConnectionAllocator createForTest( - BaseChildProcessConnection.Factory connectionFactory, String packageName, - String serviceClassName, int serviceCount) { - return new ChildConnectionAllocator( - connectionFactory, packageName, serviceClassName, serviceCount); + String packageName, String serviceClassName, int serviceCount) { + return new ChildConnectionAllocator(packageName, serviceClassName, serviceCount); } - private ChildConnectionAllocator(BaseChildProcessConnection.Factory connectionFactory, + private ChildConnectionAllocator( String packageName, String serviceClassName, int numChildServices) { - mConnectionFactory = connectionFactory; mServiceClassName = serviceClassName; - mChildProcessConnections = new BaseChildProcessConnection[numChildServices]; + mChildProcessConnections = new ChildProcessConnection[numChildServices]; mFreeConnectionIndices = new ArrayList<Integer>(numChildServices); for (int i = 0; i < numChildServices; i++) { mFreeConnectionIndices.add(i); @@ -124,9 +136,9 @@ } // Allocates or enqueues. If there are no free slots, returns null and enqueues the spawn data. - public BaseChildProcessConnection allocate(ChildSpawnData spawnData, - BaseChildProcessConnection.DeathCallback deathCallback, - Bundle childProcessCommonParameters, boolean queueIfNoSlotAvailable) { + public ChildProcessConnection allocate(ChildSpawnData spawnData, + ChildProcessConnection.DeathCallback deathCallback, Bundle childProcessCommonParameters, + boolean queueIfNoSlotAvailable) { assert LauncherThread.runningOnLauncherThread(); if (mFreeConnectionIndices.isEmpty()) { Log.d(TAG, "Ran out of services to allocate."); @@ -138,15 +150,14 @@ int slot = mFreeConnectionIndices.remove(0); assert mChildProcessConnections[slot] == null; String serviceClassName = mServiceClassName + slot; - mChildProcessConnections[slot] = - mConnectionFactory.create(spawnData.getContext(), deathCallback, serviceClassName, - childProcessCommonParameters, spawnData.getCreationParams()); + mChildProcessConnections[slot] = mConnectionFactory.createConnection( + spawnData, deathCallback, childProcessCommonParameters, serviceClassName); Log.d(TAG, "Allocator allocated a connection, name: %s, slot: %d", mServiceClassName, slot); return mChildProcessConnections[slot]; } // Also return the first ChildSpawnData in the pending queue, if any. - public ChildSpawnData free(BaseChildProcessConnection connection) { + public ChildSpawnData free(ChildProcessConnection connection) { assert LauncherThread.runningOnLauncherThread(); // mChildProcessConnections is relatively short (20 items at max at this point). // We are better of iterating than caching in a map. @@ -172,6 +183,11 @@ return mChildProcessConnections.length; } + @VisibleForTesting + void setConnectionFactoryForTesting(ConnectionFactory connectionFactory) { + mConnectionFactory = connectionFactory; + } + /** @return the count of connections managed by the allocator */ @VisibleForTesting int allocatedConnectionsCountForTesting() { @@ -180,7 +196,7 @@ } @VisibleForTesting - BaseChildProcessConnection[] connectionArrayForTesting() { + ChildProcessConnection[] connectionArrayForTesting() { return mChildProcessConnections; }
diff --git a/content/public/android/java/src/org/chromium/content/browser/BaseChildProcessConnection.java b/content/public/android/java/src/org/chromium/content/browser/ChildProcessConnection.java similarity index 68% rename from content/public/android/java/src/org/chromium/content/browser/BaseChildProcessConnection.java rename to content/public/android/java/src/org/chromium/content/browser/ChildProcessConnection.java index 77796e8..509663b 100644 --- a/content/public/android/java/src/org/chromium/content/browser/BaseChildProcessConnection.java +++ b/content/public/android/java/src/org/chromium/content/browser/ChildProcessConnection.java
@@ -32,8 +32,8 @@ /** * Manages a connection between the browser activity and a child service. */ -public abstract class BaseChildProcessConnection { - private static final String TAG = "BaseChildProcessConn"; +public class ChildProcessConnection { + private static final String TAG = "ChildProcessConn"; /** * Used to notify the consumer about disconnection of the service. This callback is provided @@ -42,7 +42,7 @@ */ interface DeathCallback { // Called on Launcher thread. - void onChildProcessDied(BaseChildProcessConnection connection); + void onChildProcessDied(ChildProcessConnection connection); } /** @@ -71,17 +71,11 @@ * Called when the connection to the service is established. * @param connecion the connection object to the child process */ - void onConnected(BaseChildProcessConnection connection); - } - - /** Used to create specialization connection instances. */ - interface Factory { - BaseChildProcessConnection create(Context context, DeathCallback deathCallback, - String serviceClassName, Bundle childProcessCommonParameters, - ChildProcessCreationParams creationParams); + void onConnected(ChildProcessConnection connection); } /** Interface representing a connection to the Android service. Can be mocked in unit-tests. */ + @VisibleForTesting protected interface ChildServiceConnection { boolean bind(); void unbind(); @@ -89,8 +83,7 @@ } /** Implementation of ChildServiceConnection that does connect to a service. */ - protected class ChildServiceConnectionImpl - implements ChildServiceConnection, ServiceConnection { + private class ChildServiceConnectionImpl implements ChildServiceConnection, ServiceConnection { private final int mBindFlags; private boolean mBound; @@ -111,14 +104,14 @@ public boolean bind() { if (!mBound) { try { - TraceEvent.begin("BaseChildProcessConnection.ChildServiceConnection.bind"); + TraceEvent.begin("ChildProcessConnection.ChildServiceConnectionImpl.bind"); Intent intent = createServiceBindIntent(); if (mChildProcessCommonParameters != null) { intent.putExtras(mChildProcessCommonParameters); } mBound = mContext.bindService(intent, this, mBindFlags); } finally { - TraceEvent.end("BaseChildProcessConnection.ChildServiceConnection.bind"); + TraceEvent.end("ChildProcessConnection.ChildServiceConnectionImpl.bind"); } } return mBound; @@ -142,7 +135,7 @@ LauncherThread.post(new Runnable() { @Override public void run() { - BaseChildProcessConnection.this.onServiceConnectedOnLauncherThread(service); + ChildProcessConnection.this.onServiceConnectedOnLauncherThread(service); } }); } @@ -153,18 +146,16 @@ LauncherThread.post(new Runnable() { @Override public void run() { - BaseChildProcessConnection.this.onServiceDisconnectedOnLauncherThread(); + ChildProcessConnection.this.onServiceDisconnectedOnLauncherThread(); } }); } } - // binding flag provided via ChildProcessCreationParams. // TODO(mnaganov): Get rid of it after the release of the next Android SDK. private static final Map<ComponentName, Boolean> sNeedsExtrabindFlagsMap = new HashMap<>(); - private final Context mContext; - private final BaseChildProcessConnection.DeathCallback mDeathCallback; + private final ChildProcessConnection.DeathCallback mDeathCallback; private final ComponentName mServiceName; // Parameters passed to the child process through the service binding intent. @@ -216,7 +207,31 @@ // Process ID of the corresponding child process. private int mPid; - protected BaseChildProcessConnection(Context context, DeathCallback deathCallback, + // Inital moderate binding. + private final ChildServiceConnection mInitialBinding; + + // Strong binding will make the service priority equal to the priority of the activity. + private final ChildServiceConnection mStrongBinding; + + // Moderate binding will make the service priority equal to the priority of a visible process + // while the app is in the foreground. + private final ChildServiceConnection mModerateBinding; + + // Low priority binding maintained in the entire lifetime of the connection, i.e. between calls + // to start() and stop(). + private final ChildServiceConnection mWaivedBinding; + + // Incremented on addStrongBinding(), decremented on removeStrongBinding(). + private int mStrongBindingCount; + + // Indicates whether the connection only has the waived binding (if the connection is unbound, + // it contains the state at time of unbinding). + private boolean mWaivedBoundOnly; + + // Set to true once unbind() was called. + private boolean mUnbound; + + protected ChildProcessConnection(Context context, DeathCallback deathCallback, String serviceClassName, Bundle childProcessCommonParameters, ChildProcessCreationParams creationParams) { assert LauncherThread.runningOnLauncherThread(); @@ -227,6 +242,13 @@ mServiceName = new ComponentName(packageName, serviceClassName); mChildProcessCommonParameters = childProcessCommonParameters; mCreationParams = creationParams; + + int defaultFlags = Context.BIND_AUTO_CREATE + | (shouldBindAsExportedService() ? Context.BIND_EXTERNAL_SERVICE : 0); + mInitialBinding = createServiceConnection(defaultFlags); + mModerateBinding = createServiceConnection(defaultFlags); + mStrongBinding = createServiceConnection(defaultFlags | Context.BIND_IMPORTANT); + mWaivedBinding = createServiceConnection(defaultFlags | Context.BIND_WAIVE_PRIORITY); } public final Context getContext() { @@ -240,11 +262,6 @@ : mContext.getPackageName(); } - public final ChildProcessCreationParams getCreationParams() { - assert LauncherThread.runningOnLauncherThread(); - return mCreationParams; - } - public final IChildProcessService getService() { assert LauncherThread.runningOnLauncherThread(); return mService; @@ -255,6 +272,10 @@ return mServiceName; } + public boolean isConnected() { + return mService != null; + } + /** * @return the connection pid, or 0 if not yet connected */ @@ -267,28 +288,29 @@ * Starts a connection to an IChildProcessService. This must be followed by a call to * setupConnection() to setup the connection parameters. start() and setupConnection() are * separate to allow to pass whatever parameters are available in start(), and complete the - * remainder later while reducing the connection setup latency. + * remainder addStrongBinding while reducing the connection setup latency. + * @param useStrongBinding whether a strong binding should be bound by default. If false, an + * initial moderate binding is used. * @param startCallback (optional) callback when the child process starts or fails to start. */ - public void start(StartCallback startCallback) { + public void start(boolean useStrongBinding, StartCallback startCallback) { assert LauncherThread.runningOnLauncherThread(); try { - TraceEvent.begin("BaseChildProcessConnection.start"); + TraceEvent.begin("ChildProcessConnection.start"); assert LauncherThread.runningOnLauncherThread(); assert mConnectionParams - == null - : "setupConnection() called before start() in BaseChildProcessConnection."; + == null : "setupConnection() called before start() in ChildProcessConnection."; mStartCallback = startCallback; - if (!bind()) { + if (!bind(useStrongBinding)) { Log.e(TAG, "Failed to establish the service connection."); // We have to notify the caller so that they can free-up associated resources. // TODO(ppi): Can we hard-fail here? - mDeathCallback.onChildProcessDied(BaseChildProcessConnection.this); + mDeathCallback.onChildProcessDied(ChildProcessConnection.this); } } finally { - TraceEvent.end("BaseChildProcessConnection.start"); + TraceEvent.end("ChildProcessConnection.start"); } } @@ -311,7 +333,7 @@ return; } try { - TraceEvent.begin("BaseChildProcessConnection.setupConnection"); + TraceEvent.begin("ChildProcessConnection.setupConnection"); mConnectionCallback = connectionCallback; mConnectionParams = new ConnectionParams(commandLine, filesToBeMapped, callback); // Run the setup if the service is already connected. If not, @@ -320,7 +342,7 @@ doConnectionSetupLocked(); } } finally { - TraceEvent.end("BaseChildProcessConnection.setupConnection"); + TraceEvent.end("ChildProcessConnection.setupConnection"); } } @@ -343,18 +365,17 @@ return; } try { - TraceEvent.begin( - "BaseChildProcessConnection.ChildServiceConnection.onServiceConnected"); + TraceEvent.begin("ChildProcessConnection.ChildServiceConnection.onServiceConnected"); mDidOnServiceConnected = true; mService = IChildProcessService.Stub.asInterface(service); StartCallback startCallback = mStartCallback; mStartCallback = null; - final boolean bindCheck = - mCreationParams != null && mCreationParams.getBindToCallerCheck(); boolean boundToUs = false; try { + boolean bindCheck = + mCreationParams != null && mCreationParams.getBindToCallerCheck(); boundToUs = bindCheck ? mService.bindToCaller() : true; } catch (RemoteException ex) { // Do not trigger the StartCallback here, since the service is already @@ -383,7 +404,7 @@ doConnectionSetupLocked(); } } finally { - TraceEvent.end("BaseChildProcessConnection.ChildServiceConnection.onServiceConnected"); + TraceEvent.end("ChildProcessConnection.ChildServiceConnection.onServiceConnected"); } } @@ -397,7 +418,7 @@ mServiceDisconnected = true; Log.w(TAG, "onServiceDisconnected (crash or killed by oom): pid=%d", mPid); stop(); // We don't want to auto-restart on crash. Let the browser do that. - mDeathCallback.onChildProcessDied(BaseChildProcessConnection.this); + mDeathCallback.onChildProcessDied(ChildProcessConnection.this); // If we have a pending connection callback, we need to communicate the failure to // the caller. if (mConnectionCallback != null) { @@ -423,7 +444,7 @@ */ private void doConnectionSetupLocked() { try { - TraceEvent.begin("BaseChildProcessConnection.doConnectionSetupLocked"); + TraceEvent.begin("ChildProcessConnection.doConnectionSetupLocked"); assert mServiceConnectComplete && mService != null; assert mConnectionParams != null; @@ -455,23 +476,142 @@ } mConnectionParams = null; } finally { - TraceEvent.end("BaseChildProcessConnection.doConnectionSetupLocked"); + TraceEvent.end("ChildProcessConnection.doConnectionSetupLocked"); } } - /** Subclasses should implement this method to bind/unbind to the actual service. */ - protected abstract boolean bind(); - protected abstract void unbind(); - - protected ChildServiceConnection createServiceConnection(int bindFlags) { + private boolean bind(boolean useStrongBinding) { assert LauncherThread.runningOnLauncherThread(); - return new ChildServiceConnectionImpl(bindFlags); + assert !mUnbound; + + boolean success = useStrongBinding ? mStrongBinding.bind() : mInitialBinding.bind(); + if (!success) return false; + + updateWaivedBoundOnlyState(); + mWaivedBinding.bind(); + return true; + } + + @VisibleForTesting + protected void unbind() { + assert LauncherThread.runningOnLauncherThread(); + mUnbound = true; + mStrongBinding.unbind(); + mWaivedBinding.unbind(); + mModerateBinding.unbind(); + mInitialBinding.unbind(); + // Note that we don't update the waived bound only state here as to preserve the state when + // disconnected. + } + + public boolean isInitialBindingBound() { + assert LauncherThread.runningOnLauncherThread(); + return mInitialBinding.isBound(); + } + + public void addInitialBinding() { + assert LauncherThread.runningOnLauncherThread(); + mInitialBinding.bind(); + updateWaivedBoundOnlyState(); + } + + public boolean isStrongBindingBound() { + assert LauncherThread.runningOnLauncherThread(); + return mStrongBinding.isBound(); + } + + public void removeInitialBinding() { + assert LauncherThread.runningOnLauncherThread(); + mInitialBinding.unbind(); + updateWaivedBoundOnlyState(); + } + + public void dropOomBindings() { + assert LauncherThread.runningOnLauncherThread(); + mInitialBinding.unbind(); + + mStrongBindingCount = 0; + mStrongBinding.unbind(); + updateWaivedBoundOnlyState(); + + mModerateBinding.unbind(); + } + + public void addStrongBinding() { + assert LauncherThread.runningOnLauncherThread(); + if (!isConnected()) { + Log.w(TAG, "The connection is not bound for %d", getPid()); + return; + } + if (mStrongBindingCount == 0) { + mStrongBinding.bind(); + updateWaivedBoundOnlyState(); + } + mStrongBindingCount++; + } + + public void removeStrongBinding() { + assert LauncherThread.runningOnLauncherThread(); + if (!isConnected()) { + Log.w(TAG, "The connection is not bound for %d", getPid()); + return; + } + assert mStrongBindingCount > 0; + mStrongBindingCount--; + if (mStrongBindingCount == 0) { + mStrongBinding.unbind(); + updateWaivedBoundOnlyState(); + } + } + + public boolean isModerateBindingBound() { + assert LauncherThread.runningOnLauncherThread(); + return mModerateBinding.isBound(); + } + + public void addModerateBinding() { + assert LauncherThread.runningOnLauncherThread(); + if (!isConnected()) { + Log.w(TAG, "The connection is not bound for %d", getPid()); + return; + } + mModerateBinding.bind(); + updateWaivedBoundOnlyState(); + } + + public void removeModerateBinding() { + assert LauncherThread.runningOnLauncherThread(); + if (!isConnected()) { + Log.w(TAG, "The connection is not bound for %d", getPid()); + return; + } + mModerateBinding.unbind(); + updateWaivedBoundOnlyState(); + } + + /** + * @return true if the connection is bound and only bound with the waived binding or if the + * connection is unbound and was only bound with the waived binding when it disconnected. + */ + public boolean isWaivedBoundOnlyOrWasWhenDied() { + // WARNING: this method can be called from a thread other than the launcher thread. + // Note that it returns the current waived bound only state and is racy. This not really + // preventable without changing the caller's API, short of blocking. + return mWaivedBoundOnly; + } + + // Should be called every time the mInitialBinding or mStrongBinding are bound/unbound. + private void updateWaivedBoundOnlyState() { + if (!mUnbound) { + mWaivedBoundOnly = !mInitialBinding.isBound() && !mStrongBinding.isBound() + && !mModerateBinding.isBound(); + } } protected boolean shouldBindAsExportedService() { assert LauncherThread.runningOnLauncherThread(); - return Build.VERSION.SDK_INT >= Build.VERSION_CODES.N && getCreationParams() != null - && getCreationParams().getIsExternalService() + return Build.VERSION.SDK_INT >= Build.VERSION_CODES.N && mCreationParams != null + && mCreationParams.getIsExternalService() && isExportedService(getContext(), getServiceName()); } @@ -493,12 +633,13 @@ } @VisibleForTesting - public void crashServiceForTesting() throws RemoteException { - mService.crashIntentionallyForTesting(); + protected ChildServiceConnection createServiceConnection(int bindFlags) { + assert LauncherThread.runningOnLauncherThread(); + return new ChildServiceConnectionImpl(bindFlags); } @VisibleForTesting - boolean isConnected() { - return mService != null; + public void crashServiceForTesting() throws RemoteException { + mService.crashIntentionallyForTesting(); } }
diff --git a/content/public/android/java/src/org/chromium/content/browser/ChildProcessLauncher.java b/content/public/android/java/src/org/chromium/content/browser/ChildProcessLauncher.java index d668456..c88a5d63 100644 --- a/content/public/android/java/src/org/chromium/content/browser/ChildProcessLauncher.java +++ b/content/public/android/java/src/org/chromium/content/browser/ChildProcessLauncher.java
@@ -51,7 +51,7 @@ * Implemented by ChildProcessLauncherHelper. */ public interface LaunchCallback { - void onChildProcessStarted(BaseChildProcessConnection connection); + void onChildProcessStarted(ChildProcessConnection connection); } private static final boolean SPARE_CONNECTION_ALWAYS_IN_FOREGROUND = false; @@ -61,14 +61,14 @@ sSandboxedChildConnectionAllocatorMap = new HashMap<>(); // Map from a connection to its ChildConnectionAllocator. - private static final Map<BaseChildProcessConnection, ChildConnectionAllocator> + private static final Map<ChildProcessConnection, ChildConnectionAllocator> sConnectionsToAllocatorMap = new HashMap<>(); // Allocator used for non-sandboxed services. private static ChildConnectionAllocator sPrivilegedChildConnectionAllocator; - // Used by test to override the default sandboxed service allocator settings. - private static BaseChildProcessConnection.Factory sSandboxedServiceFactoryForTesting; + // Used by tests to override the default sandboxed service allocator settings. + private static ChildConnectionAllocator.ConnectionFactory sSandboxedServiceFactoryForTesting; private static int sSandboxedServicesCountForTesting = -1; private static String sSandboxedServicesNameForTesting; @@ -79,8 +79,7 @@ if (!sandboxed) { if (sPrivilegedChildConnectionAllocator == null) { sPrivilegedChildConnectionAllocator = ChildConnectionAllocator.create(context, - ImportantChildProcessConnection.FACTORY, packageName, - PRIVILEGED_SERVICES_NAME_KEY, NUM_PRIVILEGED_SERVICES_KEY); + packageName, PRIVILEGED_SERVICES_NAME_KEY, NUM_PRIVILEGED_SERVICES_KEY); } return sPrivilegedChildConnectionAllocator; } @@ -93,20 +92,19 @@ ChildConnectionAllocator connectionAllocator = null; if (sSandboxedServicesCountForTesting != -1) { // Testing case where allocator settings are overriden. - BaseChildProcessConnection.Factory factory = - sSandboxedServiceFactoryForTesting == null - ? ManagedChildProcessConnection.FACTORY - : sSandboxedServiceFactoryForTesting; String serviceName = !TextUtils.isEmpty(sSandboxedServicesNameForTesting) ? sSandboxedServicesNameForTesting : SandboxedProcessService.class.getName(); connectionAllocator = ChildConnectionAllocator.createForTest( - factory, packageName, serviceName, sSandboxedServicesCountForTesting); + packageName, serviceName, sSandboxedServicesCountForTesting); } else { - connectionAllocator = ChildConnectionAllocator.create(context, - ManagedChildProcessConnection.FACTORY, packageName, + connectionAllocator = ChildConnectionAllocator.create(context, packageName, SANDBOXED_SERVICES_NAME_KEY, NUM_SANDBOXED_SERVICES_KEY); } + if (sSandboxedServiceFactoryForTesting != null) { + connectionAllocator.setConnectionFactoryForTesting( + sSandboxedServiceFactoryForTesting); + } sSandboxedChildConnectionAllocatorMap.put(packageName, connectionAllocator); } return sSandboxedChildConnectionAllocatorMap.get(packageName); @@ -115,13 +113,13 @@ } @VisibleForTesting - static BaseChildProcessConnection allocateConnection( + static ChildProcessConnection allocateConnection( ChildSpawnData spawnData, Bundle childProcessCommonParams, boolean forWarmUp) { assert LauncherThread.runningOnLauncherThread(); - BaseChildProcessConnection.DeathCallback deathCallback = - new BaseChildProcessConnection.DeathCallback() { + ChildProcessConnection.DeathCallback deathCallback = + new ChildProcessConnection.DeathCallback() { @Override - public void onChildProcessDied(BaseChildProcessConnection connection) { + public void onChildProcessDied(ChildProcessConnection connection) { assert LauncherThread.runningOnLauncherThread(); if (connection.getPid() != 0) { stop(connection.getPid()); @@ -137,7 +135,7 @@ creationParams != null ? creationParams.getPackageName() : context.getPackageName(); ChildConnectionAllocator allocator = getConnectionAllocator(context, packageName, inSandbox); - BaseChildProcessConnection connection = + ChildProcessConnection connection = allocator.allocate(spawnData, deathCallback, childProcessCommonParams, !forWarmUp); sConnectionsToAllocatorMap.put(connection, allocator); return connection; @@ -184,17 +182,19 @@ } @VisibleForTesting - static BaseChildProcessConnection allocateBoundConnection(ChildSpawnData spawnData, - BaseChildProcessConnection.StartCallback startCallback, boolean forWarmUp) { + static ChildProcessConnection allocateBoundConnection(ChildSpawnData spawnData, + ChildProcessConnection.StartCallback startCallback, boolean forWarmUp) { assert LauncherThread.runningOnLauncherThread(); final Context context = spawnData.getContext(); final boolean inSandbox = spawnData.isInSandbox(); final ChildProcessCreationParams creationParams = spawnData.getCreationParams(); - BaseChildProcessConnection connection = allocateConnection( + ChildProcessConnection connection = allocateConnection( spawnData, createCommonParamsBundle(spawnData.getCreationParams()), forWarmUp); if (connection != null) { - connection.start(startCallback); + // Non sandboxed processes are privileged processes that should be strongly bound. + boolean useStrongBinding = !inSandbox; + connection.start(useStrongBinding, startCallback); String packageName = creationParams != null ? creationParams.getPackageName() : context.getPackageName(); @@ -212,7 +212,7 @@ private static final long FREE_CONNECTION_DELAY_MILLIS = 1; - private static void freeConnection(BaseChildProcessConnection connection) { + private static void freeConnection(ChildProcessConnection connection) { assert LauncherThread.runningOnLauncherThread(); if (connection == sSpareSandboxedConnection) clearSpareConnection(); @@ -221,7 +221,7 @@ // alive when it's been unbound for a short time. If a new connection to the same service // is bound at that point, the process is reused and bad things happen (mostly static // variables are set when we don't expect them to). - final BaseChildProcessConnection conn = connection; + final ChildProcessConnection conn = connection; LauncherThread.postDelayed(new Runnable() { @Override public void run() { @@ -246,8 +246,7 @@ } // Map from pid to ChildService connection. - private static Map<Integer, BaseChildProcessConnection> sServiceMap = - new ConcurrentHashMap<Integer, BaseChildProcessConnection>(); + private static Map<Integer, ChildProcessConnection> sServiceMap = new ConcurrentHashMap<>(); // These variables are used for the warm up sandboxed connection. // |sSpareSandboxedConnection| is non-null when there is a pending connection. Note it's cleared @@ -257,9 +256,9 @@ // |sSpareConnectionStartCallback| is the chained StartCallback. This is also used to determine // if there is already a child process launch that's used this this connection. @SuppressLint("StaticFieldLeak") - private static BaseChildProcessConnection sSpareSandboxedConnection; + private static ChildProcessConnection sSpareSandboxedConnection; private static boolean sSpareConnectionStarting; - private static BaseChildProcessConnection.StartCallback sSpareConnectionStartCallback; + private static ChildProcessConnection.StartCallback sSpareConnectionStartCallback; // Manages oom bindings used to bind chind services. Lazily initialized by getBindingManager() private static BindingManager sBindingManager; @@ -354,8 +353,8 @@ if (sSpareSandboxedConnection != null) return; ChildProcessCreationParams params = ChildProcessCreationParams.getDefault(); - BaseChildProcessConnection.StartCallback startCallback = - new BaseChildProcessConnection.StartCallback() { + ChildProcessConnection.StartCallback startCallback = + new ChildProcessConnection.StartCallback() { @Override public void onChildStarted() { assert LauncherThread.runningOnLauncherThread(); @@ -422,7 +421,7 @@ if (!ContentSwitches.SWITCH_RENDERER_PROCESS.equals(processType)) { if (params != null && !params.getPackageName().equals(context.getPackageName())) { // WebViews and WebAPKs have renderer processes running in their applications. - // When launching these renderer processes, {@link ManagedChildProcessConnection} + // When launching these renderer processes, {@link ChildProcessConnection} // requires the package name of the application which holds the renderer process. // Therefore, the package name in ChildProcessCreationParams could be the package // name of WebViews, WebAPKs, or Chrome, depending on the host application. @@ -450,7 +449,7 @@ } @VisibleForTesting - public static BaseChildProcessConnection startInternal(final Context context, + public static ChildProcessConnection startInternal(final Context context, final String[] commandLine, final FileDescriptorInfo[] filesToBeMapped, final LaunchCallback launchCallback, final IBinder childProcessCallback, final boolean inSandbox, final boolean alwaysInForeground, @@ -459,18 +458,18 @@ try { TraceEvent.begin("ChildProcessLauncher.startInternal"); - BaseChildProcessConnection allocatedConnection = null; + ChildProcessConnection allocatedConnection = null; String packageName = creationParams != null ? creationParams.getPackageName() : context.getPackageName(); - BaseChildProcessConnection.StartCallback startCallback = - new BaseChildProcessConnection.StartCallback() { + ChildProcessConnection.StartCallback startCallback = + new ChildProcessConnection.StartCallback() { @Override public void onChildStarted() {} @Override public void onChildStartFailed() { assert LauncherThread.runningOnLauncherThread(); - Log.e(TAG, "BaseChildProcessConnection.start failed, trying again"); + Log.e(TAG, "ChildProcessConnection.start failed, trying again"); LauncherThread.post(new Runnable() { @Override public void run() { @@ -512,8 +511,9 @@ } } + boolean addToBindingmanager = inSandbox; triggerConnectionSetup(allocatedConnection, commandLine, filesToBeMapped, - childProcessCallback, launchCallback); + childProcessCallback, launchCallback, addToBindingmanager); return allocatedConnection; } finally { TraceEvent.end("ChildProcessLauncher.startInternal"); @@ -538,23 +538,23 @@ } @VisibleForTesting - static void triggerConnectionSetup(final BaseChildProcessConnection connection, + static void triggerConnectionSetup(final ChildProcessConnection connection, String[] commandLine, FileDescriptorInfo[] filesToBeMapped, - final IBinder childProcessCallback, final LaunchCallback launchCallback) { + final IBinder childProcessCallback, final LaunchCallback launchCallback, + final boolean addToBindingmanager) { assert LauncherThread.runningOnLauncherThread(); Log.d(TAG, "Setting up connection to process, connection name=%s", connection.getServiceName()); - BaseChildProcessConnection.ConnectionCallback connectionCallback = - new BaseChildProcessConnection.ConnectionCallback() { + ChildProcessConnection.ConnectionCallback connectionCallback = + new ChildProcessConnection.ConnectionCallback() { @Override - public void onConnected(BaseChildProcessConnection connection) { + public void onConnected(ChildProcessConnection connection) { assert LauncherThread.runningOnLauncherThread(); if (connection != null) { int pid = connection.getPid(); Log.d(TAG, "on connect callback, pid=%d", pid); - if (connection instanceof ManagedChildProcessConnection) { - getBindingManager().addNewConnection( - pid, (ManagedChildProcessConnection) connection); + if (addToBindingmanager) { + getBindingManager().addNewConnection(pid, connection); } sServiceMap.put(pid, connection); } @@ -579,7 +579,7 @@ static void stop(int pid) { assert LauncherThread.runningOnLauncherThread(); Log.d(TAG, "stopping child connection: pid=%d", pid); - BaseChildProcessConnection connection = sServiceMap.remove(pid); + ChildProcessConnection connection = sServiceMap.remove(pid); if (connection == null) { // Can happen for single process. return; @@ -606,7 +606,8 @@ @VisibleForTesting public static void setSandboxServicesSettingsForTesting( - BaseChildProcessConnection.Factory factory, int serviceCount, String serviceName) { + ChildConnectionAllocator.ConnectionFactory factory, int serviceCount, + String serviceName) { sSandboxedServiceFactoryForTesting = factory; sSandboxedServicesCountForTesting = serviceCount; sSandboxedServicesNameForTesting = serviceName; @@ -621,7 +622,7 @@ if (sServiceMap.get(pid) == null) return false; try { - ((ManagedChildProcessConnection) sServiceMap.get(pid)).crashServiceForTesting(); + sServiceMap.get(pid).crashServiceForTesting(); } catch (RemoteException ex) { return false; }
diff --git a/content/public/android/java/src/org/chromium/content/browser/ChildProcessLauncherHelper.java b/content/public/android/java/src/org/chromium/content/browser/ChildProcessLauncherHelper.java index 3ff2afc..d810afd 100644 --- a/content/public/android/java/src/org/chromium/content/browser/ChildProcessLauncherHelper.java +++ b/content/public/android/java/src/org/chromium/content/browser/ChildProcessLauncherHelper.java
@@ -30,7 +30,7 @@ // Note native pointer is only guaranteed live until nativeOnChildProcessStarted. private long mNativeChildProcessLauncherHelper; - private BaseChildProcessConnection mChildProcessConnection; + private ChildProcessConnection mChildProcessConnection; @CalledByNative private static FileDescriptorInfo makeFdInfo( @@ -66,7 +66,7 @@ ChildProcessLauncher.start(ContextUtils.getApplicationContext(), paramId, commandLine, filesToBeMapped, new ChildProcessLauncher.LaunchCallback() { @Override - public void onChildProcessStarted(BaseChildProcessConnection connection) { + public void onChildProcessStarted(ChildProcessConnection connection) { mChildProcessConnection = connection; if (mNativeChildProcessLauncherHelper != 0) { nativeOnChildProcessStarted( @@ -91,15 +91,10 @@ return false; } - if (mChildProcessConnection instanceof ImportantChildProcessConnection) { - // The connection was bound as BIND_IMPORTANT. This should prevent it from being killed - // when the app is on the foreground (that's our best guess, but there is no absolute - // guarantee). - return ChildProcessLauncher.isApplicationInForeground(); - } - - return ((ManagedChildProcessConnection) mChildProcessConnection) - .isOomProtectedOrWasWhenDied(); + // We consider the process to be child protected if it has a strong or moderate binding and + // the app is in the foreground. + return ChildProcessLauncher.isApplicationInForeground() + && !mChildProcessConnection.isWaivedBoundOnlyOrWasWhenDied(); } @CalledByNative
diff --git a/content/public/android/java/src/org/chromium/content/browser/ImportantChildProcessConnection.java b/content/public/android/java/src/org/chromium/content/browser/ImportantChildProcessConnection.java deleted file mode 100644 index 700f00af..0000000 --- a/content/public/android/java/src/org/chromium/content/browser/ImportantChildProcessConnection.java +++ /dev/null
@@ -1,50 +0,0 @@ -// Copyright 2013 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.content.browser; - -import android.content.Context; -import android.os.Bundle; - -import org.chromium.base.process_launcher.ChildProcessCreationParams; - -/** - * A connection that is bound as important, meaning the framework brings it to the foreground - * process level when the app is. - */ -public class ImportantChildProcessConnection extends BaseChildProcessConnection { - public static final Factory FACTORY = new BaseChildProcessConnection.Factory() { - @Override - public BaseChildProcessConnection create(Context context, DeathCallback deathCallback, - String serviceClassName, Bundle childProcessCommonParameters, - ChildProcessCreationParams creationParams) { - return new ImportantChildProcessConnection(context, deathCallback, serviceClassName, - childProcessCommonParameters, creationParams); - } - }; - - private final ChildServiceConnection mBinding; - - private ImportantChildProcessConnection(Context context, DeathCallback deathCallback, - String serviceClassName, Bundle childProcessCommonParameters, - ChildProcessCreationParams creationParams) { - super(context, deathCallback, serviceClassName, childProcessCommonParameters, - creationParams); - int flags = Context.BIND_AUTO_CREATE | Context.BIND_IMPORTANT; - if (shouldBindAsExportedService()) { - flags |= Context.BIND_EXTERNAL_SERVICE; - } - mBinding = createServiceConnection(flags); - } - - @Override - public boolean bind() { - return mBinding.bind(); - } - - @Override - public void unbind() { - mBinding.unbind(); - } -}
diff --git a/content/public/android/java/src/org/chromium/content/browser/ManagedChildProcessConnection.java b/content/public/android/java/src/org/chromium/content/browser/ManagedChildProcessConnection.java deleted file mode 100644 index 0726181..0000000 --- a/content/public/android/java/src/org/chromium/content/browser/ManagedChildProcessConnection.java +++ /dev/null
@@ -1,203 +0,0 @@ -// Copyright 2013 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.content.browser; - -import android.content.Context; -import android.os.Bundle; - -import org.chromium.base.Log; -import org.chromium.base.VisibleForTesting; -import org.chromium.base.process_launcher.ChildProcessCreationParams; - -/** - * ManagedChildProcessConnection is a connection to a child service that can hold several bindings - * to the service so it can be more or less agressively protected against OOM. - * Accessed from the launcher thread. (but for isOomProtectedOrWasWhenDied()). - */ -public class ManagedChildProcessConnection extends BaseChildProcessConnection { - private static final String TAG = "ManChildProcessConn"; - - public static final Factory FACTORY = new BaseChildProcessConnection.Factory() { - @Override - public BaseChildProcessConnection create(Context context, DeathCallback deathCallback, - String serviceClassName, Bundle childProcessCommonParameters, - ChildProcessCreationParams creationParams) { - assert LauncherThread.runningOnLauncherThread(); - return new ManagedChildProcessConnection(context, deathCallback, serviceClassName, - childProcessCommonParameters, creationParams); - } - }; - - // Initial binding protects the newly spawned process from being killed before it is put to use, - // it is maintained between calls to start() and removeInitialBinding(). - private final ChildServiceConnection mInitialBinding; - - // Strong binding will make the service priority equal to the priority of the activity. We want - // the OS to be able to kill background renderers as it kills other background apps, so strong - // bindings are maintained only for services that are active at the moment (between - // addStrongBinding() and removeStrongBinding()). - private final ChildServiceConnection mStrongBinding; - - // Low priority binding maintained in the entire lifetime of the connection, i.e. between calls - // to start() and stop(). - private final ChildServiceConnection mWaivedBinding; - - // Incremented on addStrongBinding(), decremented on removeStrongBinding(). - private int mStrongBindingCount; - - // Moderate binding will make the service priority equal to the priority of a visible process - // while the app is in the foreground. It will stay bound only while the app is in the - // foreground to protect a background process from the system out-of-memory killer. - private final ChildServiceConnection mModerateBinding; - - // Indicates whether the connection is OOM protected (if the connection is unbound, it contains - // the state at time of unbinding). - private boolean mOomProtected; - - // Set to true once unbind() was called. - private boolean mUnbound; - - @VisibleForTesting - ManagedChildProcessConnection(Context context, DeathCallback deathCallback, - String serviceClassName, Bundle childProcessCommonParameters, - ChildProcessCreationParams creationParams) { - super(context, deathCallback, serviceClassName, childProcessCommonParameters, - creationParams); - - int initialFlags = Context.BIND_AUTO_CREATE; - int extraBindFlags = shouldBindAsExportedService() ? Context.BIND_EXTERNAL_SERVICE : 0; - mInitialBinding = createServiceConnection(initialFlags | extraBindFlags); - mStrongBinding = createServiceConnection( - Context.BIND_AUTO_CREATE | Context.BIND_IMPORTANT | extraBindFlags); - mWaivedBinding = createServiceConnection( - Context.BIND_AUTO_CREATE | Context.BIND_WAIVE_PRIORITY | extraBindFlags); - mModerateBinding = createServiceConnection(Context.BIND_AUTO_CREATE | extraBindFlags); - } - - @Override - protected boolean bind() { - assert LauncherThread.runningOnLauncherThread(); - assert !mUnbound; - if (!mInitialBinding.bind()) { - return false; - } - updateOomProtectedState(); - mWaivedBinding.bind(); - return true; - } - - @Override - public void unbind() { - assert LauncherThread.runningOnLauncherThread(); - mUnbound = true; - mInitialBinding.unbind(); - mStrongBinding.unbind(); - // Note that we don't update the OOM state here as to preserve the last OOM state. - mWaivedBinding.unbind(); - mModerateBinding.unbind(); - mStrongBindingCount = 0; - } - - public boolean isInitialBindingBound() { - assert LauncherThread.runningOnLauncherThread(); - return mInitialBinding.isBound(); - } - - public boolean isStrongBindingBound() { - assert LauncherThread.runningOnLauncherThread(); - return mStrongBinding.isBound(); - } - - public void addInitialBinding() { - assert LauncherThread.runningOnLauncherThread(); - mInitialBinding.bind(); - updateOomProtectedState(); - } - - public void removeInitialBinding() { - assert LauncherThread.runningOnLauncherThread(); - mInitialBinding.unbind(); - updateOomProtectedState(); - } - - /** - * @return true if the connection is bound and OOM protected or was OOM protected when unbound. - */ - public boolean isOomProtectedOrWasWhenDied() { - // WARNING: this method can be called from a thread other than the launcher thread. - // Note that it returns the current OOM protected state and is racy. This not really - // preventable without changing the caller's API, short of blocking. - return mOomProtected; - } - - public void dropOomBindings() { - assert LauncherThread.runningOnLauncherThread(); - mInitialBinding.unbind(); - - mStrongBindingCount = 0; - mStrongBinding.unbind(); - updateOomProtectedState(); - - mModerateBinding.unbind(); - } - - public void addStrongBinding() { - assert LauncherThread.runningOnLauncherThread(); - if (!isConnected()) { - Log.w(TAG, "The connection is not bound for %d", getPid()); - return; - } - if (mStrongBindingCount == 0) { - mStrongBinding.bind(); - updateOomProtectedState(); - } - mStrongBindingCount++; - } - - public void removeStrongBinding() { - assert LauncherThread.runningOnLauncherThread(); - if (!isConnected()) { - Log.w(TAG, "The connection is not bound for %d", getPid()); - return; - } - assert mStrongBindingCount > 0; - mStrongBindingCount--; - if (mStrongBindingCount == 0) { - mStrongBinding.unbind(); - updateOomProtectedState(); - } - updateOomProtectedState(); - } - - public boolean isModerateBindingBound() { - assert LauncherThread.runningOnLauncherThread(); - return mModerateBinding.isBound(); - } - - public void addModerateBinding() { - assert LauncherThread.runningOnLauncherThread(); - if (!isConnected()) { - Log.w(TAG, "The connection is not bound for %d", getPid()); - return; - } - mModerateBinding.bind(); - } - - public void removeModerateBinding() { - assert LauncherThread.runningOnLauncherThread(); - if (!isConnected()) { - Log.w(TAG, "The connection is not bound for %d", getPid()); - return; - } - mModerateBinding.unbind(); - } - - // Should be called every time the mInitialBinding or mStrongBinding are bound/unbound. - private void updateOomProtectedState() { - if (!mUnbound) { - mOomProtected = mInitialBinding.isBound() || mStrongBinding.isBound(); - } - } -}
diff --git a/content/public/android/javatests/src/org/chromium/content/browser/ChildProcessLauncherIntegrationTest.java b/content/public/android/javatests/src/org/chromium/content/browser/ChildProcessLauncherIntegrationTest.java index 7e857db4..974f648 100644 --- a/content/public/android/javatests/src/org/chromium/content/browser/ChildProcessLauncherIntegrationTest.java +++ b/content/public/android/javatests/src/org/chromium/content/browser/ChildProcessLauncherIntegrationTest.java
@@ -37,18 +37,38 @@ public final ContentShellActivityTestRule mActivityTestRule = new ContentShellActivityTestRule(); - private static class TestManagedChildProcessConnection extends ManagedChildProcessConnection { + private static class TestChildProcessConnectionFactory + implements ChildConnectionAllocator.ConnectionFactory { + private final List<TestChildProcessConnection> mConnections = new ArrayList<>(); + + @Override + public ChildProcessConnection createConnection(ChildSpawnData spawnData, + ChildProcessConnection.DeathCallback deathCallback, + Bundle childProcessCommonParameters, String serviceClassName) { + TestChildProcessConnection connection = new TestChildProcessConnection( + spawnData.getContext(), deathCallback, serviceClassName, + childProcessCommonParameters, spawnData.getCreationParams()); + mConnections.add(connection); + return connection; + } + + public List<TestChildProcessConnection> getConnections() { + return mConnections; + } + } + + private static class TestChildProcessConnection extends ChildProcessConnection { private RuntimeException mRemovedBothInitialAndStrongBinding; - public TestManagedChildProcessConnection(Context context, - BaseChildProcessConnection.DeathCallback deathCallback, String serviceClassName, + public TestChildProcessConnection(Context context, + ChildProcessConnection.DeathCallback deathCallback, String serviceClassName, Bundle childProcessCommonParameters, ChildProcessCreationParams creationParams) { super(context, deathCallback, serviceClassName, childProcessCommonParameters, creationParams); } @Override - public void unbind() { + protected void unbind() { super.unbind(); if (mRemovedBothInitialAndStrongBinding == null) { mRemovedBothInitialAndStrongBinding = new RuntimeException("unbind"); @@ -86,31 +106,11 @@ } } - private static class TestChildProcessConnectionFactory - implements BaseChildProcessConnection.Factory { - private final List<TestManagedChildProcessConnection> mConnections = new ArrayList<>(); - - @Override - public BaseChildProcessConnection create(Context context, - BaseChildProcessConnection.DeathCallback deathCallback, String serviceClassName, - Bundle childProcessCommonParameters, ChildProcessCreationParams creationParams) { - TestManagedChildProcessConnection connection = - new TestManagedChildProcessConnection(context, deathCallback, serviceClassName, - childProcessCommonParameters, creationParams); - mConnections.add(connection); - return connection; - } - - public List<TestManagedChildProcessConnection> getConnections() { - return mConnections; - } - } - @Test @MediumTest public void testCrossDomainNavigationDoNotLoseImportance() throws Throwable { final TestChildProcessConnectionFactory factory = new TestChildProcessConnectionFactory(); - final List<TestManagedChildProcessConnection> connections = factory.getConnections(); + final List<TestChildProcessConnection> connections = factory.getConnections(); ChildProcessLauncher.setSandboxServicesSettingsForTesting(factory, 10 /* arbitrary number, only realy need 2 */, null /* use default service name */);
diff --git a/content/public/android/javatests/src/org/chromium/content/browser/ChildProcessLauncherTest.java b/content/public/android/javatests/src/org/chromium/content/browser/ChildProcessLauncherTest.java index 1a9fbec..fca55b4 100644 --- a/content/public/android/javatests/src/org/chromium/content/browser/ChildProcessLauncherTest.java +++ b/content/public/android/javatests/src/org/chromium/content/browser/ChildProcessLauncherTest.java
@@ -103,7 +103,7 @@ Assert.assertEquals(0, ChildProcessLauncher.connectedServicesCountForTesting()); // Start and connect to a new service. - final BaseChildProcessConnection connection = startConnection(); + final ChildProcessConnection connection = startConnection(); Assert.assertEquals(1, allocatedChromeSandboxedConnectionsCount()); // Verify that the service is not yet set up. @@ -139,7 +139,7 @@ Assert.assertEquals(0, allocatedChromeSandboxedConnectionsCount()); // Start and connect to a new service. - final BaseChildProcessConnection connection = startConnection(); + final ChildProcessConnection connection = startConnection(); Assert.assertEquals(1, allocatedChromeSandboxedConnectionsCount()); // Initiate the connection setup. @@ -194,7 +194,7 @@ Assert.assertEquals(0, allocatedChromeSandboxedConnectionsCount()); // Start and connect to a new service. - final BaseChildProcessConnection connection = startConnection(); + final ChildProcessConnection connection = startConnection(); Assert.assertEquals(1, allocatedChromeSandboxedConnectionsCount()); // Queue up a new spawn request. There is no way to kill the pending connection, leak it @@ -270,10 +270,10 @@ Assert.assertEquals(0, allocatedChromeSandboxedConnectionsCount()); // Start and connect to a new service of an external APK. - BaseChildProcessConnection externalApkConnection = + ChildProcessConnection externalApkConnection = allocateConnection(EXTERNAL_APK_PACKAGE_NAME); // Start and connect to a new service for a regular tab. - BaseChildProcessConnection tabConnection = allocateConnection(appContext.getPackageName()); + ChildProcessConnection tabConnection = allocateConnection(appContext.getPackageName()); // Verify that one connection is allocated for an external APK and a regular tab // respectively. @@ -308,17 +308,17 @@ appContext, EXTERNAL_APK_PACKAGE_NAME)); // Setup a connection for an external APK to reach the maximum allowed connection number. - BaseChildProcessConnection externalApkConnection = + ChildProcessConnection externalApkConnection = allocateConnection(EXTERNAL_APK_PACKAGE_NAME); Assert.assertNotNull(externalApkConnection); // Verify that there isn't any connection available for the external APK. - BaseChildProcessConnection exceedNumberExternalApkConnection = + ChildProcessConnection exceedNumberExternalApkConnection = allocateConnection(EXTERNAL_APK_PACKAGE_NAME); Assert.assertNull(exceedNumberExternalApkConnection); // Verify that we can still allocate connection for a regular tab. - BaseChildProcessConnection tabConnection = allocateConnection(appContext.getPackageName()); + ChildProcessConnection tabConnection = allocateConnection(appContext.getPackageName()); Assert.assertNotNull(tabConnection); } @@ -408,9 +408,8 @@ final ChildProcessCreationParams creationParams = new ChildProcessCreationParams( context.getPackageName(), false /* isExternalService */, LibraryProcessType.PROCESS_CHILD, true /* bindToCallerCheck */); - final BaseChildProcessConnection conn = - ChildProcessLauncherTestUtils.startInternalForTesting( - context, sProcessWaitArguments, new FileDescriptorInfo[0], creationParams); + final ChildProcessConnection conn = ChildProcessLauncherTestUtils.startInternalForTesting( + context, sProcessWaitArguments, new FileDescriptorInfo[0], creationParams); CriteriaHelper.pollInstrumentationThread( new Criteria("Failed waiting for instrumentation-bound service") { @@ -422,7 +421,7 @@ Assert.assertEquals(0, ChildProcessLauncherTestUtils.getConnectionServiceNumber(conn)); - final BaseChildProcessConnection[] sandboxedConnections = + final ChildProcessConnection[] sandboxedConnections = getSandboxedConnectionArrayForTesting(context, context.getPackageName()); // Wait for the retry to succeed. @@ -432,7 +431,7 @@ public boolean isSatisfied() { boolean allChildrenConnected = true; for (int i = 0; i <= 1; ++i) { - BaseChildProcessConnection conn = sandboxedConnections[i]; + ChildProcessConnection conn = sandboxedConnections[i]; allChildrenConnected &= conn != null && ChildProcessLauncherTestUtils.getConnectionService(conn) != null; @@ -443,7 +442,7 @@ // Check that only two connections are created. for (int i = 0; i < sandboxedConnections.length; ++i) { - BaseChildProcessConnection sandboxedConn = sandboxedConnections[i]; + ChildProcessConnection sandboxedConn = sandboxedConnections[i]; if (i <= 1) { Assert.assertNotNull(sandboxedConn); Assert.assertNotNull( @@ -454,7 +453,7 @@ } Assert.assertTrue(conn == sandboxedConnections[0]); - final BaseChildProcessConnection retryConn = sandboxedConnections[1]; + final ChildProcessConnection retryConn = sandboxedConnections[1]; Assert.assertFalse(conn == retryConn); @@ -496,7 +495,7 @@ public void run() { Assert.assertEquals(1, allocatedChromeSandboxedConnectionsCount()); - final BaseChildProcessConnection conn = + final ChildProcessConnection conn = ChildProcessLauncherTestUtils.startInternalForTesting( context, new String[0], new FileDescriptorInfo[0], null); Assert.assertEquals( @@ -538,10 +537,10 @@ }); } - private BaseChildProcessConnection startConnection() { + private ChildProcessConnection startConnection() { // Allocate a new connection. Context context = InstrumentationRegistry.getInstrumentation().getTargetContext(); - final BaseChildProcessConnection connection = allocateBoundConnectionForTesting( + final ChildProcessConnection connection = allocateBoundConnectionForTesting( context, getDefaultChildProcessCreationParams(context.getPackageName())); // Wait for the service to connect. @@ -564,12 +563,12 @@ filesToMap, null /* launchCallback */); } - private static BaseChildProcessConnection allocateBoundConnectionForTesting( + private static ChildProcessConnection allocateBoundConnectionForTesting( final Context context, final ChildProcessCreationParams creationParams) { return ChildProcessLauncherTestUtils.runOnLauncherAndGetResult( - new Callable<BaseChildProcessConnection>() { + new Callable<ChildProcessConnection>() { @Override - public BaseChildProcessConnection call() { + public ChildProcessConnection call() { return ChildProcessLauncher.allocateBoundConnection( new ChildSpawnData(context, null /* commandLine */, null /* filesToBeMapped */, null /* LaunchCallback */, @@ -585,11 +584,11 @@ * but doesn't really start the connection to bind a service. It is for testing whether the * connection is allocated properly for different application packages. */ - private BaseChildProcessConnection allocateConnection(final String packageName) { + private ChildProcessConnection allocateConnection(final String packageName) { return ChildProcessLauncherTestUtils.runOnLauncherAndGetResult( - new Callable<BaseChildProcessConnection>() { + new Callable<ChildProcessConnection>() { @Override - public BaseChildProcessConnection call() { + public ChildProcessConnection call() { // Allocate a new connection. Context context = InstrumentationRegistry.getTargetContext(); ChildProcessCreationParams creationParams = @@ -636,12 +635,12 @@ }); } - private static BaseChildProcessConnection[] getSandboxedConnectionArrayForTesting( + private static ChildProcessConnection[] getSandboxedConnectionArrayForTesting( final Context context, final String packageName) { return ChildProcessLauncherTestUtils.runOnLauncherAndGetResult( - new Callable<BaseChildProcessConnection[]>() { + new Callable<ChildProcessConnection[]>() { @Override - public BaseChildProcessConnection[] call() { + public ChildProcessConnection[] call() { return ChildProcessLauncher .getConnectionAllocator(context, packageName, true /*isSandboxed */) .connectionArrayForTesting(); @@ -675,13 +674,13 @@ LibraryProcessType.PROCESS_CHILD, false /* bindToCallerCheck */); } - private void triggerConnectionSetup(final BaseChildProcessConnection connection) { + private void triggerConnectionSetup(final ChildProcessConnection connection) { ChildProcessLauncherTestUtils.runOnLauncherThreadBlocking(new Runnable() { @Override public void run() { ChildProcessLauncher.triggerConnectionSetup(connection, sProcessWaitArguments, new FileDescriptorInfo[0], null /* launchCallback */, - null /* childProcessCallback */); + null /* childProcessCallback */, true /* addToBindingManager */); } }); }
diff --git a/content/public/android/junit/src/org/chromium/content/browser/BindingManagerImplTest.java b/content/public/android/junit/src/org/chromium/content/browser/BindingManagerImplTest.java index b1a4f9f..74d789ff 100644 --- a/content/public/android/junit/src/org/chromium/content/browser/BindingManagerImplTest.java +++ b/content/public/android/junit/src/org/chromium/content/browser/BindingManagerImplTest.java
@@ -28,8 +28,7 @@ import java.util.ArrayList; /** - * Unit tests for BindingManagerImpl. The tests run agains mock ChildProcessConnection - * implementation, thus testing only the BindingManagerImpl itself. + * Unit tests for BindingManagerImpl and ChildProcessConnection. * * Default property of being low-end device is overriden, so that both low-end and high-end policies * are tested. @@ -38,7 +37,7 @@ @Config(manifest = Config.NONE) public class BindingManagerImplTest { private static class MockChildServiceConnection - implements BaseChildProcessConnection.ChildServiceConnection { + implements ChildProcessConnection.ChildServiceConnection { private boolean mBound; @Override @@ -58,7 +57,7 @@ } } - private static class TestChildProcessConnection extends ManagedChildProcessConnection { + private static class TestChildProcessConnection extends ChildProcessConnection { private final int mPid; private boolean mConnected; @@ -87,8 +86,8 @@ // We don't have a real service so we have to mock the connection status. @Override - public void start(StartCallback startCallback) { - super.start(startCallback); + public void start(boolean useStrongBinding, StartCallback startCallback) { + super.start(useStrongBinding, startCallback); mConnected = true; } @@ -104,6 +103,17 @@ } } + // Creates a mocked ChildProcessConnection that is optionally added to a BindingManager. + private static ChildProcessConnection createTestChildProcessConnection( + int pid, BindingManager manager) { + ChildProcessConnection connection = new TestChildProcessConnection(pid); + connection.start(false /* useStrongBinding */, null /* startCallback */); + if (manager != null) { + manager.addNewConnection(pid, connection); + } + return connection; + } + /** * Helper class that stores a manager along with its text label. This is used for tests that * iterate over all managers to indicate which manager was being tested when an assertion @@ -168,18 +178,16 @@ BindingManagerImpl manager = mLowEndManager; // Add a connection to the manager. - TestChildProcessConnection firstConnection = new TestChildProcessConnection(1); - firstConnection.start(null /* startCallback */); - manager.addNewConnection(firstConnection.getPid(), firstConnection); + ChildProcessConnection firstConnection = + createTestChildProcessConnection(1 /* pid */, manager); // Bind a strong binding on the connection. manager.setPriority(firstConnection.getPid(), true /* foreground */, false /* boost */); Assert.assertTrue(firstConnection.isStrongBindingBound()); // Add a new connection. - TestChildProcessConnection secondConnection = new TestChildProcessConnection(2); - secondConnection.start(null /* startCallback */); - manager.addNewConnection(secondConnection.getPid(), secondConnection); + ChildProcessConnection secondConnection = + createTestChildProcessConnection(2 /* pid */, manager); // Verify that the strong binding for the first connection wasn't dropped. Assert.assertTrue(firstConnection.isStrongBindingBound()); @@ -188,6 +196,7 @@ // got used in foreground. manager.setPriority(secondConnection.getPid(), true /* foreground */, false /* boost */); Assert.assertFalse(firstConnection.isStrongBindingBound()); + Assert.assertTrue(secondConnection.isStrongBindingBound()); } /** @@ -198,12 +207,11 @@ @Feature({"ProcessManagement"}) public void testStrongBindingRemovalOnLowEnd() throws Throwable { // This test applies only to the low-end manager. - final BindingManagerImpl manager = mLowEndManager; + BindingManagerImpl manager = mLowEndManager; // Add a connection to the manager. - final TestChildProcessConnection connection = new TestChildProcessConnection(1); - connection.start(null /* startCallback */); - manager.addNewConnection(connection.getPid(), connection); + ChildProcessConnection connection = createTestChildProcessConnection(1 /* pid */, manager); + Assert.assertTrue(connection.isInitialBindingBound()); Assert.assertFalse(connection.isStrongBindingBound()); // Add a strong binding. @@ -223,12 +231,11 @@ @Feature({"ProcessManagement"}) public void testStrongBindingRemovalOnHighEnd() throws Throwable { // This test applies only to the high-end manager. - final BindingManagerImpl manager = mHighEndManager; + BindingManagerImpl manager = mHighEndManager; // Add a connection to the manager. - final TestChildProcessConnection connection = new TestChildProcessConnection(1); - connection.start(null /* startCallback */); - manager.addNewConnection(connection.getPid(), connection); + ChildProcessConnection connection = createTestChildProcessConnection(1 /* pid */, manager); + Assert.assertTrue(connection.isInitialBindingBound()); Assert.assertFalse(connection.isStrongBindingBound()); // Add a strong binding, verify that the initial binding is not removed. @@ -254,12 +261,10 @@ @Feature({"ProcessManagement"}) public void testStrongBindingRemovalWithModerateBinding() throws Throwable { // This test applies only to the moderate-binding manager. - final BindingManagerImpl manager = mModerateBindingManager; + BindingManagerImpl manager = mModerateBindingManager; // Add a connection to the manager and start it. - final TestChildProcessConnection connection = new TestChildProcessConnection(1); - connection.start(null /* startCallback */); - manager.addNewConnection(connection.getPid(), connection); + ChildProcessConnection connection = createTestChildProcessConnection(1 /* pid */, manager); Assert.assertTrue(connection.isInitialBindingBound()); Assert.assertFalse(connection.isStrongBindingBound()); @@ -285,33 +290,37 @@ /** * This test corresponds to a process crash scenario: after a process dies and its connection is - * cleared, isOomProtectedOrWasWhenDied() may be called on the connection to decide if it was a - * crash or out-of-memory kill. + * cleared, isWaivedBoundOnlyOrWasWhenDied() may be called on the connection to decide if it was + * a crash or out-of-memory kill. */ @Test @Feature({"ProcessManagement"}) - public void testIsOomProtected() { + public void testIsWaivedBoundOnly() { // This test applies to low-end, high-end and moderate-binding policies. for (ManagerEntry managerEntry : mAllManagers) { BindingManagerImpl manager = managerEntry.mManager; String message = managerEntry.getErrorMessage(); // Add a connection to the manager. - TestChildProcessConnection connection = new TestChildProcessConnection(1); - connection.start(null /* startCallback */); - manager.addNewConnection(connection.getPid(), connection); + ChildProcessConnection connection = + createTestChildProcessConnection(1 /* pid */, manager); - // Initial binding is an oom binding. - Assert.assertTrue(message, connection.isOomProtectedOrWasWhenDied()); + // Initial binding is a moderate binding. + Assert.assertFalse(message, connection.isWaivedBoundOnlyOrWasWhenDied()); - // After initial binding is removed, the connection is no longer oom protected. + // After initial binding is removed, the connection is no longer waived bound only. manager.setPriority(connection.getPid(), false /* foreground */, false /* boost */); ShadowLooper.runUiThreadTasksIncludingDelayedTasks(); - Assert.assertFalse(message, connection.isOomProtectedOrWasWhenDied()); + if (managerEntry.mManager == mModerateBindingManager) { + // The moderate binding manager adds a moderate binding. + Assert.assertFalse(message, connection.isWaivedBoundOnlyOrWasWhenDied()); + } else { + Assert.assertTrue(message, connection.isWaivedBoundOnlyOrWasWhenDied()); + } - // Add a strong binding, restoring the oom protection. + // Add a strong binding. manager.setPriority(connection.getPid(), true /* foreground */, false /* boost */); - Assert.assertTrue(message, connection.isOomProtectedOrWasWhenDied()); + Assert.assertFalse(message, connection.isWaivedBoundOnlyOrWasWhenDied()); // Simulate a process crash - clear a connection in binding manager and remove the // bindings. @@ -320,11 +329,11 @@ Assert.assertTrue(manager.isConnectionCleared(connection.getPid())); connection.stop(); - // Verify that the connection doesn't keep any oom bindings, but the manager reports the - // oom status as protected. + // Verify that manager reports the the connection was waived bound. Assert.assertFalse(message, connection.isInitialBindingBound()); + Assert.assertFalse(message, connection.isModerateBindingBound()); Assert.assertFalse(message, connection.isStrongBindingBound()); - Assert.assertTrue(message, connection.isOomProtectedOrWasWhenDied()); + Assert.assertFalse(message, connection.isWaivedBoundOnlyOrWasWhenDied()); } } @@ -347,25 +356,22 @@ String message = managerEntry.getErrorMessage(); // Add two connections, bind and release each. - TestChildProcessConnection firstConnection = new TestChildProcessConnection(1); - firstConnection.start(null /* startCallback */); - manager.addNewConnection(firstConnection.getPid(), firstConnection); + ChildProcessConnection firstConnection = + createTestChildProcessConnection(1 /* pid */, manager); manager.setPriority(firstConnection.getPid(), true /* foreground */, false /* boost */); manager.setPriority( firstConnection.getPid(), false /* foreground */, false /* boost */); - TestChildProcessConnection secondConnection = new TestChildProcessConnection(2); - secondConnection.start(null /* startCallback */); - manager.addNewConnection(secondConnection.getPid(), secondConnection); + ChildProcessConnection secondConnection = + createTestChildProcessConnection(2 /* pid */, manager); manager.setPriority( secondConnection.getPid(), true /* foreground */, false /* boost */); manager.setPriority( secondConnection.getPid(), false /* foreground */, false /* boost */); // Add third connection, do not bind it. - TestChildProcessConnection thirdConnection = new TestChildProcessConnection(3); - thirdConnection.start(null /* startCallback */); - manager.addNewConnection(thirdConnection.getPid(), thirdConnection); + ChildProcessConnection thirdConnection = + createTestChildProcessConnection(3 /* pid */, manager); manager.setPriority( thirdConnection.getPid(), false /* foreground */, false /* boost */); @@ -403,16 +409,14 @@ // This test applies only to the moderate-binding manager. final BindingManagerImpl manager = mModerateBindingManager; - TestChildProcessConnection[] connections = new TestChildProcessConnection[3]; + ChildProcessConnection[] connections = new ChildProcessConnection[3]; for (int i = 0; i < connections.length; i++) { - connections[i] = new TestChildProcessConnection(i + 1); - connections[i].start(null /* startCallback */); - manager.addNewConnection(connections[i].getPid(), connections[i]); + connections[i] = createTestChildProcessConnection(i + 1 /* pid */, manager); } // Verify that each connection has a moderate binding after binding and releasing a strong // binding. - for (TestChildProcessConnection connection : connections) { + for (ChildProcessConnection connection : connections) { manager.setPriority(connection.getPid(), true /* foreground */, false /* boost */); manager.setPriority(connection.getPid(), false /* foreground */, false /* boost */); ShadowLooper.runUiThreadTasksIncludingDelayedTasks(); @@ -421,9 +425,8 @@ // Exclude lastInForeground because it will be kept in foreground when onSentToBackground() // is called as |mLastInForeground|. - TestChildProcessConnection lastInForeground = new TestChildProcessConnection(0); - manager.addNewConnection(lastInForeground.getPid(), lastInForeground); - lastInForeground.start(null /* startCallback */); + ChildProcessConnection lastInForeground = + createTestChildProcessConnection(0 /* pid */, manager); manager.setPriority(lastInForeground.getPid(), true /* foreground */, false /* boost */); manager.setPriority(lastInForeground.getPid(), false /* foreground */, false /* boost */); @@ -431,34 +434,34 @@ // Verify that leaving the application for a short time doesn't clear the moderate bindings. manager.onSentToBackground(); - for (TestChildProcessConnection connection : connections) { + for (ChildProcessConnection connection : connections) { Assert.assertTrue(connection.isModerateBindingBound()); } Assert.assertTrue(lastInForeground.isStrongBindingBound()); Assert.assertFalse(lastInForeground.isModerateBindingBound()); manager.onBroughtToForeground(); ShadowLooper.runUiThreadTasksIncludingDelayedTasks(); - for (TestChildProcessConnection connection : connections) { + for (ChildProcessConnection connection : connections) { Assert.assertTrue(connection.isModerateBindingBound()); } // Call onSentToBackground() and verify that all the moderate bindings drop after some // delay. manager.onSentToBackground(); - for (TestChildProcessConnection connection : connections) { + for (ChildProcessConnection connection : connections) { Assert.assertTrue(connection.isModerateBindingBound()); } Assert.assertTrue(lastInForeground.isStrongBindingBound()); Assert.assertFalse(lastInForeground.isModerateBindingBound()); ShadowLooper.runUiThreadTasksIncludingDelayedTasks(); - for (TestChildProcessConnection connection : connections) { + for (ChildProcessConnection connection : connections) { Assert.assertFalse(connection.isModerateBindingBound()); } // Call onBroughtToForeground() and verify that the previous moderate bindings aren't // recovered. manager.onBroughtToForeground(); - for (TestChildProcessConnection connection : connections) { + for (ChildProcessConnection connection : connections) { Assert.assertFalse(connection.isModerateBindingBound()); } } @@ -472,16 +475,14 @@ final Application app = mActivity.getApplication(); final BindingManagerImpl manager = mModerateBindingManager; - TestChildProcessConnection[] connections = new TestChildProcessConnection[4]; + ChildProcessConnection[] connections = new ChildProcessConnection[4]; for (int i = 0; i < connections.length; i++) { - connections[i] = new TestChildProcessConnection(i + 1); - connections[i].start(null /* startCallback */); - manager.addNewConnection(connections[i].getPid(), connections[i]); + connections[i] = createTestChildProcessConnection(i + 1 /* pid */, manager); } // Verify that each connection has a moderate binding after binding and releasing a strong // binding. - for (TestChildProcessConnection connection : connections) { + for (ChildProcessConnection connection : connections) { manager.setPriority(connection.getPid(), true /* foreground */, false /* boost */); manager.setPriority(connection.getPid(), false /* foreground */, false /* boost */); ShadowLooper.runUiThreadTasksIncludingDelayedTasks(); @@ -490,7 +491,7 @@ // Call onLowMemory() and verify that all the moderate bindings drop. app.onLowMemory(); - for (TestChildProcessConnection connection : connections) { + for (ChildProcessConnection connection : connections) { Assert.assertFalse(connection.isModerateBindingBound()); } } @@ -512,18 +513,16 @@ levelAndExpectedVictimCountList.add( new Pair<Integer, Integer>(TRIM_MEMORY_RUNNING_CRITICAL, 4)); - TestChildProcessConnection[] connections = new TestChildProcessConnection[4]; + ChildProcessConnection[] connections = new ChildProcessConnection[4]; for (int i = 0; i < connections.length; i++) { - connections[i] = new TestChildProcessConnection(i + 1); - connections[i].start(null /* startCallback */); - manager.addNewConnection(connections[i].getPid(), connections[i]); + connections[i] = createTestChildProcessConnection(i + 1 /* pid */, manager); } for (Pair<Integer, Integer> pair : levelAndExpectedVictimCountList) { String message = "Failed for the level=" + pair.first; // Verify that each connection has a moderate binding after binding and releasing a // strong binding. - for (TestChildProcessConnection connection : connections) { + for (ChildProcessConnection connection : connections) { manager.setPriority(connection.getPid(), true /* foreground */, false /* boost */); manager.setPriority(connection.getPid(), false /* foreground */, false /* boost */); ShadowLooper.runUiThreadTasksIncludingDelayedTasks(); @@ -548,16 +547,14 @@ // This test applies only to the moderate-binding manager. final BindingManagerImpl manager = mModerateBindingManager; - TestChildProcessConnection[] connections = new TestChildProcessConnection[4]; + ChildProcessConnection[] connections = new ChildProcessConnection[4]; for (int i = 0; i < connections.length; i++) { - connections[i] = new TestChildProcessConnection(i + 1); - connections[i].start(null /* startCallback */); - manager.addNewConnection(connections[i].getPid(), connections[i]); + connections[i] = createTestChildProcessConnection(i + 1 /* pid */, manager); } // Verify that each connection has a moderate binding after binding and releasing a strong // binding. - for (TestChildProcessConnection connection : connections) { + for (ChildProcessConnection connection : connections) { manager.setPriority(connection.getPid(), true /* foreground */, false /* boost */); manager.setPriority(connection.getPid(), false /* foreground */, false /* boost */); ShadowLooper.runUiThreadTasksIncludingDelayedTasks(); @@ -567,7 +564,7 @@ // Call BindingManager.releaseAllModerateBindings() and verify that all the moderate // bindings drop. manager.releaseAllModerateBindings(); - for (TestChildProcessConnection connection : connections) { + for (ChildProcessConnection connection : connections) { Assert.assertFalse(connection.isModerateBindingBound()); } } @@ -582,9 +579,7 @@ BindingManagerImpl manager = BindingManagerImpl.createBindingManagerForTesting(false); manager.startModerateBindingManagement(mActivity, 4); - TestChildProcessConnection connection = new TestChildProcessConnection(0); - connection.start(null /* startCallback */); - manager.addNewConnection(connection.getPid(), connection); + ChildProcessConnection connection = createTestChildProcessConnection(0 /* pid */, manager); Assert.assertTrue(connection.isInitialBindingBound()); Assert.assertFalse(connection.isModerateBindingBound()); @@ -603,9 +598,7 @@ BindingManagerImpl manager = BindingManagerImpl.createBindingManagerForTesting(false); manager.startModerateBindingManagement(mActivity, 4); - TestChildProcessConnection connection = new TestChildProcessConnection(0); - connection.start(null /* startCallback */); - manager.addNewConnection(connection.getPid(), connection); + ChildProcessConnection connection = createTestChildProcessConnection(0 /* pid */, manager); Assert.assertTrue(connection.isInitialBindingBound()); Assert.assertFalse(connection.isStrongBindingBound()); Assert.assertFalse(connection.isModerateBindingBound()); @@ -626,9 +619,7 @@ BindingManagerImpl manager = BindingManagerImpl.createBindingManagerForTesting(false); manager.startModerateBindingManagement(mActivity, 4); - TestChildProcessConnection connection = new TestChildProcessConnection(0); - connection.start(null /* startCallback */); - manager.addNewConnection(connection.getPid(), connection); + ChildProcessConnection connection = createTestChildProcessConnection(0, manager); manager.setPriority(connection.getPid(), false /* foreground */, false /* boost */); Assert.assertTrue(connection.isModerateBindingBound()); @@ -640,4 +631,4 @@ manager.onBroughtToForeground(); Assert.assertFalse(connection.isModerateBindingBound()); } -} +} \ No newline at end of file
diff --git a/content/public/browser/render_widget_host.h b/content/public/browser/render_widget_host.h index f2f43504..830df64 100644 --- a/content/public/browser/render_widget_host.h +++ b/content/public/browser/render_widget_host.h
@@ -25,6 +25,10 @@ class WebMouseWheelEvent; } +namespace ui { +class LatencyInfo; +} + namespace content { struct CursorInfo; @@ -166,6 +170,9 @@ const blink::WebMouseWheelEvent& wheel_event) = 0; virtual void ForwardKeyboardEvent( const NativeWebKeyboardEvent& key_event) = 0; + virtual void ForwardKeyboardEventWithLatencyInfo( + const NativeWebKeyboardEvent& key_event, + const ui::LatencyInfo& latency_info) = 0; virtual void ForwardGestureEvent( const blink::WebGestureEvent& gesture_event) = 0;
diff --git a/content/public/common/content_features.cc b/content/public/common/content_features.cc index 06089b3..45766502 100644 --- a/content/public/common/content_features.cc +++ b/content/public/common/content_features.cc
@@ -244,7 +244,14 @@ "VibrateRequiresUserGesture", base::FEATURE_ENABLED_BY_DEFAULT}; // Enables VR UI. -const base::Feature kVrShell{"VrShell", base::FEATURE_DISABLED_BY_DEFAULT}; +const base::Feature kVrShell { + "VrShell", +#if defined(OS_ANDROID) + base::FEATURE_ENABLED_BY_DEFAULT +#else + base::FEATURE_DISABLED_BY_DEFAULT +#endif +}; // Enable WebAssembly structured cloning. // http://webassembly.org/
diff --git a/content/renderer/OWNERS b/content/renderer/OWNERS index 502a1a2..d83f872 100644 --- a/content/renderer/OWNERS +++ b/content/renderer/OWNERS
@@ -1,5 +1,5 @@ # For Blink API usage -esprehn@chromium.org +dglazkov@chromium.org # For Android aelias@chromium.org
diff --git a/content/shell/android/shell_apk/src/org/chromium/content_shell_apk/ChildProcessLauncherTestHelperService.java b/content/shell/android/shell_apk/src/org/chromium/content_shell_apk/ChildProcessLauncherTestHelperService.java index e5b52b8..7687d33 100644 --- a/content/shell/android/shell_apk/src/org/chromium/content_shell_apk/ChildProcessLauncherTestHelperService.java +++ b/content/shell/android/shell_apk/src/org/chromium/content_shell_apk/ChildProcessLauncherTestHelperService.java
@@ -20,7 +20,7 @@ import org.chromium.base.library_loader.ProcessInitException; import org.chromium.base.process_launcher.ChildProcessCreationParams; import org.chromium.base.process_launcher.FileDescriptorInfo; -import org.chromium.content.browser.BaseChildProcessConnection; +import org.chromium.content.browser.ChildProcessConnection; /** * A Service that assists the ChildProcessLauncherTest that responds to one message, which @@ -70,9 +70,8 @@ final boolean bindToCaller = true; ChildProcessCreationParams params = new ChildProcessCreationParams( getPackageName(), false, LibraryProcessType.PROCESS_CHILD, bindToCaller); - final BaseChildProcessConnection conn = - ChildProcessLauncherTestUtils.startInternalForTesting( - this, commandLine, new FileDescriptorInfo[0], params); + final ChildProcessConnection conn = ChildProcessLauncherTestUtils.startInternalForTesting( + this, commandLine, new FileDescriptorInfo[0], params); // Poll the connection until it is set up. The main test in ChildProcessLauncherTest, which // has bound the connection to this service, manages the timeout via the lifetime of this
diff --git a/content/shell/android/shell_apk/src/org/chromium/content_shell_apk/ChildProcessLauncherTestUtils.java b/content/shell/android/shell_apk/src/org/chromium/content_shell_apk/ChildProcessLauncherTestUtils.java index 086dfd6..8bd087c 100644 --- a/content/shell/android/shell_apk/src/org/chromium/content_shell_apk/ChildProcessLauncherTestUtils.java +++ b/content/shell/android/shell_apk/src/org/chromium/content_shell_apk/ChildProcessLauncherTestUtils.java
@@ -9,7 +9,7 @@ import org.chromium.base.process_launcher.ChildProcessCreationParams; import org.chromium.base.process_launcher.FileDescriptorInfo; import org.chromium.base.process_launcher.IChildProcessService; -import org.chromium.content.browser.BaseChildProcessConnection; +import org.chromium.content.browser.ChildProcessConnection; import org.chromium.content.browser.ChildProcessLauncher; import org.chromium.content.browser.LauncherThread; @@ -55,12 +55,12 @@ } } - public static BaseChildProcessConnection startInternalForTesting(final Context context, + public static ChildProcessConnection startInternalForTesting(final Context context, final String[] commandLine, final FileDescriptorInfo[] filesToMap, final ChildProcessCreationParams params) { - return runOnLauncherAndGetResult(new Callable<BaseChildProcessConnection>() { + return runOnLauncherAndGetResult(new Callable<ChildProcessConnection>() { @Override - public BaseChildProcessConnection call() { + public ChildProcessConnection call() { return ChildProcessLauncher.startInternal(context, commandLine, filesToMap, null /* launchCallback */, null /* childProcessCallback */, true /* inSandbox */, false /* alwaysInForeground */, params); @@ -69,7 +69,7 @@ } // Retrieves the PID of the passed in connection on the launcher thread as to not assert. - public static int getConnectionPid(final BaseChildProcessConnection connection) { + public static int getConnectionPid(final ChildProcessConnection connection) { return runOnLauncherAndGetResult(new Callable<Integer>() { @Override public Integer call() { @@ -80,7 +80,7 @@ // Retrieves the service number of the passed in connection from its service name, or -1 if the // service number could not be determined. - public static int getConnectionServiceNumber(final BaseChildProcessConnection connection) { + public static int getConnectionServiceNumber(final ChildProcessConnection connection) { String serviceName = getConnectionServiceName(connection); // The service name ends up with the service number. StringBuilder numberString = new StringBuilder(); @@ -100,7 +100,7 @@ // Retrieves the service number of the passed in connection on the launcher thread as to not // assert. - public static String getConnectionServiceName(final BaseChildProcessConnection connection) { + public static String getConnectionServiceName(final ChildProcessConnection connection) { return runOnLauncherAndGetResult(new Callable<String>() { @Override public String call() { @@ -111,7 +111,7 @@ // Retrieves the service of the passed in connection on the launcher thread as to not assert. public static IChildProcessService getConnectionService( - final BaseChildProcessConnection connection) { + final ChildProcessConnection connection) { return runOnLauncherAndGetResult(new Callable<IChildProcessService>() { @Override public IChildProcessService call() {
diff --git a/content/test/gpu/gpu_tests/webgl_conformance_revision.txt b/content/test/gpu/gpu_tests/webgl_conformance_revision.txt index 873d47b..00b68c7a 100644 --- a/content/test/gpu/gpu_tests/webgl_conformance_revision.txt +++ b/content/test/gpu/gpu_tests/webgl_conformance_revision.txt
@@ -1,3 +1,3 @@ # AUTOGENERATED FILE - DO NOT EDIT # SEE roll_webgl_conformance.py -Current webgl revision 6517159d2016833417582d46a8dfc4e941ac0bd2 +Current webgl revision 87aaf44c5333e8b209baf5e11baa325b79ddeb62
diff --git a/device/bluetooth/bluetooth_remote_gatt_characteristic_mac.h b/device/bluetooth/bluetooth_remote_gatt_characteristic_mac.h index e02bc82..1f54f86 100644 --- a/device/bluetooth/bluetooth_remote_gatt_characteristic_mac.h +++ b/device/bluetooth/bluetooth_remote_gatt_characteristic_mac.h
@@ -136,6 +136,8 @@ std::unordered_map<std::string, std::unique_ptr<BluetoothRemoteGattDescriptorMac>> gatt_descriptor_macs_; + + base::WeakPtrFactory<BluetoothRemoteGattCharacteristicMac> weak_ptr_factory_; }; // Stream operator for logging.
diff --git a/device/bluetooth/bluetooth_remote_gatt_characteristic_mac.mm b/device/bluetooth/bluetooth_remote_gatt_characteristic_mac.mm index 2f135e6..3c6e5a2 100644 --- a/device/bluetooth/bluetooth_remote_gatt_characteristic_mac.mm +++ b/device/bluetooth/bluetooth_remote_gatt_characteristic_mac.mm
@@ -72,7 +72,8 @@ : is_discovery_complete_(false), discovery_pending_count_(0), gatt_service_(gatt_service), - cb_characteristic_(cb_characteristic, base::scoped_policy::RETAIN) { + cb_characteristic_(cb_characteristic, base::scoped_policy::RETAIN), + weak_ptr_factory_(this) { uuid_ = BluetoothAdapterMac::BluetoothUUIDWithCBUUID( [cb_characteristic_.get() UUID]); identifier_ = base::SysNSStringToUTF8( @@ -207,7 +208,7 @@ base::ThreadTaskRunnerHandle::Get()->PostTask( FROM_HERE, base::Bind(&BluetoothRemoteGattCharacteristicMac::DidWriteValue, - base::Unretained(this), nil)); + weak_ptr_factory_.GetWeakPtr(), nil)); } }
diff --git a/device/bluetooth/bluetooth_remote_gatt_characteristic_unittest.cc b/device/bluetooth/bluetooth_remote_gatt_characteristic_unittest.cc index 614f70e..587c3ebd 100644 --- a/device/bluetooth/bluetooth_remote_gatt_characteristic_unittest.cc +++ b/device/bluetooth/bluetooth_remote_gatt_characteristic_unittest.cc
@@ -2413,6 +2413,31 @@ } #endif // defined(OS_ANDROID) +#if defined(OS_MACOSX) +// Tests that writing without response during a disconnect results in an error. +// Only applies to macOS whose events arrive all on the UI thread. See other +// *DuringDisconnect tests for Android and Windows whose events arrive on a +// different thread. +TEST_F(BluetoothRemoteGattCharacteristicTest, + WriteWithoutResponseDuringDisconnect) { + if (!PlatformSupportsLowEnergy()) { + LOG(WARNING) << "Low Energy Bluetooth unavailable, skipping unit test."; + return; + } + ASSERT_NO_FATAL_FAILURE(FakeCharacteristicBoilerplate( + BluetoothRemoteGattCharacteristic::PROPERTY_WRITE_WITHOUT_RESPONSE)); + + characteristic1_->WriteRemoteCharacteristic( + std::vector<uint8_t>(), GetCallback(Call::NOT_EXPECTED), + GetGattErrorCallback(Call::EXPECTED)); + SimulateGattDisconnection(device_); + + base::RunLoop().RunUntilIdle(); + EXPECT_EQ(BluetoothRemoteGattService::GATT_ERROR_FAILED, + last_gatt_error_code_); +} +#endif // defined(OS_MACOSX) + #if defined(OS_ANDROID) // Tests that start notifications requests after a device disconnects but before // the disconnect task runs result in an error.
diff --git a/device/gamepad/gamepad_monitor.cc b/device/gamepad/gamepad_monitor.cc index 0f85717..7ba2e83 100644 --- a/device/gamepad/gamepad_monitor.cc +++ b/device/gamepad/gamepad_monitor.cc
@@ -4,6 +4,8 @@ #include "device/gamepad/gamepad_monitor.h" +#include <utility> + #include "base/memory/ptr_util.h" #include "base/memory/shared_memory.h" #include "device/gamepad/gamepad_service.h" @@ -38,23 +40,21 @@ gamepad_observer_->GamepadDisconnected(index, gamepad); } -void GamepadMonitor::GamepadStartPolling( - const GamepadStartPollingCallback& callback) { +void GamepadMonitor::GamepadStartPolling(GamepadStartPollingCallback callback) { DCHECK(!is_started_); is_started_ = true; GamepadService* service = GamepadService::GetInstance(); service->ConsumerBecameActive(this); - callback.Run(service->GetSharedBufferHandle()); + std::move(callback).Run(service->GetSharedBufferHandle()); } -void GamepadMonitor::GamepadStopPolling( - const GamepadStopPollingCallback& callback) { +void GamepadMonitor::GamepadStopPolling(GamepadStopPollingCallback callback) { DCHECK(is_started_); is_started_ = false; GamepadService::GetInstance()->ConsumerBecameInactive(this); - callback.Run(); + std::move(callback).Run(); } void GamepadMonitor::SetObserver(mojom::GamepadObserverPtr gamepad_observer) {
diff --git a/device/gamepad/gamepad_monitor.h b/device/gamepad/gamepad_monitor.h index fa4d374..19d0d0d 100644 --- a/device/gamepad/gamepad_monitor.h +++ b/device/gamepad/gamepad_monitor.h
@@ -32,9 +32,8 @@ void OnGamepadDisconnected(unsigned index, const Gamepad& gamepad) override; // mojom::GamepadMonitor implementation. - void GamepadStartPolling( - const GamepadStartPollingCallback& callback) override; - void GamepadStopPolling(const GamepadStopPollingCallback& callback) override; + void GamepadStartPolling(GamepadStartPollingCallback callback) override; + void GamepadStopPolling(GamepadStopPollingCallback callback) override; void SetObserver(mojom::GamepadObserverPtr gamepad_observer) override; private:
diff --git a/device/gamepad/public/interfaces/BUILD.gn b/device/gamepad/public/interfaces/BUILD.gn index c1f78e4a..ffbf359 100644 --- a/device/gamepad/public/interfaces/BUILD.gn +++ b/device/gamepad/public/interfaces/BUILD.gn
@@ -8,9 +8,6 @@ sources = [ "gamepad.mojom", ] - - # TODO(crbug.com/714018): Convert the implementation to use OnceCallback. - use_once_callback = false } mojom("gamepad_struct_traits_test") { @@ -21,7 +18,4 @@ public_deps = [ ":interfaces", ] - - # TODO(crbug.com/714018): Convert the implementation to use OnceCallback. - use_once_callback = false }
diff --git a/device/gamepad/public/interfaces/gamepad_struct_traits_unittest.cc b/device/gamepad/public/interfaces/gamepad_struct_traits_unittest.cc index f1c5c27c..5a731fe 100644 --- a/device/gamepad/public/interfaces/gamepad_struct_traits_unittest.cc +++ b/device/gamepad/public/interfaces/gamepad_struct_traits_unittest.cc
@@ -2,6 +2,8 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +#include <utility> + #include "base/message_loop/message_loop.h" #include "base/run_loop.h" #include "device/gamepad/public/cpp/gamepad.h" @@ -175,9 +177,8 @@ protected: GamepadStructTraitsTest() : binding_(this) {} - void PassGamepad(const Gamepad& send, - const PassGamepadCallback& callback) override { - callback.Run(send); + void PassGamepad(const Gamepad& send, PassGamepadCallback callback) override { + std::move(callback).Run(send); } mojom::GamepadStructTraitsTestPtr GetGamepadStructTraitsTestProxy() {
diff --git a/extensions/common/permissions/permissions_data.cc b/extensions/common/permissions/permissions_data.cc index 2002b29..245040e 100644 --- a/extensions/common/permissions/permissions_data.cc +++ b/extensions/common/permissions/permissions_data.cc
@@ -158,10 +158,9 @@ } const URLPatternSet& PermissionsData::PolicyBlockedHostsUnsafe() const { - DCHECK(!thread_checker_ || thread_checker_->CalledOnValidThread()); + runtime_lock_.AssertAcquired(); if (uses_default_policy_host_restrictions) return default_policy_blocked_hosts(); - runtime_lock_.AssertAcquired(); return policy_blocked_hosts_unsafe_; } @@ -171,10 +170,9 @@ } const URLPatternSet& PermissionsData::PolicyAllowedHostsUnsafe() const { - DCHECK(!thread_checker_ || thread_checker_->CalledOnValidThread()); + runtime_lock_.AssertAcquired(); if (uses_default_policy_host_restrictions) return default_policy_allowed_hosts(); - runtime_lock_.AssertAcquired(); return policy_allowed_hosts_unsafe_; }
diff --git a/headless/BUILD.gn b/headless/BUILD.gn index 719ee2790..49124bc 100644 --- a/headless/BUILD.gn +++ b/headless/BUILD.gn
@@ -200,6 +200,20 @@ ] } +if (headless_fontconfig_utils) { + static_library("headless_fontconfig_utils") { + sources = [ + "public/util/fontconfig.cc", + "public/util/fontconfig.h", + ] + + deps = [ + "//third_party/fontconfig", + "//third_party/freetype", + ] + } +} + component("headless") { sources = [ "app/headless_shell_switches.cc", @@ -380,6 +394,10 @@ deps += [ "//ui/ozone" ] } + if (headless_fontconfig_utils) { + deps += [ ":headless_fontconfig_utils" ] + } + configs += [ ":headless_implementation" ] }
diff --git a/headless/headless.gni b/headless/headless.gni index 0cc77229..ab0b2d10 100644 --- a/headless/headless.gni +++ b/headless/headless.gni
@@ -5,4 +5,7 @@ declare_args() { # Embed resource.pak file into the binary for easier distribution. headless_use_embedded_resources = false + + # Provide bindings for font loading for headless embedders. + headless_fontconfig_utils = false }
diff --git a/headless/public/util/fontconfig.cc b/headless/public/util/fontconfig.cc new file mode 100644 index 0000000..d859c19 --- /dev/null +++ b/headless/public/util/fontconfig.cc
@@ -0,0 +1,119 @@ +// Copyright 2017 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. + +#include "headless/public/util/fontconfig.h" + +// Should be included before freetype.h. +#include <ft2build.h> + +#include <dirent.h> +#include <fontconfig/fontconfig.h> +#include <freetype/freetype.h> +#include <set> +#include <string> + +#include "base/logging.h" + +namespace headless { +namespace { +void GetFontFileNames(const FcFontSet* font_set, + std::set<std::string>* file_names) { + if (font_set == NULL) + return; + for (int i = 0; i < font_set->nfont; ++i) { + FcPattern* pattern = font_set->fonts[i]; + FcValue font_file; + if (FcPatternGet(pattern, "file", 0, &font_file) == FcResultMatch) { + file_names->insert(reinterpret_cast<const char*>(font_file.u.s)); + } else { + VLOG(1) << "Failed to find filename."; + FcPatternPrint(pattern); + } + } +} +FcConfig* g_config = nullptr; +} // namespace + +void InitFonts(const char* fontconfig_path) { + // The following is roughly equivalent to calling FcInit(). We jump through + // a bunch of hoops here to avoid using fontconfig's directory scanning + // logic. The problem with fontconfig is that it follows symlinks when doing + // recursive directory scans. + // + // The approach below ignores any <dir>...</dir> entries in fonts.conf. This + // is deliberate. Specifying dirs is problematic because they're either + // absolute or relative to our process's current working directory which + // could be anything. Instead we assume that all font files will be in the + // same directory as fonts.conf. We'll scan + load them here. + FcConfig* config = FcConfigCreate(); + g_config = config; + CHECK(config); + + // FcConfigParseAndLoad is a seriously goofy function. Depending on whether + // name passed in begins with a slash, it will treat it either as a file name + // to be found in the directory where it expects to find the font + // configuration OR it will will treat it as a directory where it expects to + // find fonts.conf. The latter behavior is the one we want. Passing + // fontconfig_path via the environment is a quick and dirty way to get + // uniform behavior regardless whether it's a relative path or not. + setenv("FONTCONFIG_PATH", fontconfig_path, 1); + CHECK(FcConfigParseAndLoad(config, nullptr, FcTrue)) + << "Failed to load font configuration. FONTCONFIG_PATH=" + << fontconfig_path; + + DIR* fc_dir = opendir(fontconfig_path); + CHECK(fc_dir) << "Failed to open font directory " << fontconfig_path << ": " + << strerror(errno); + + // The fonts must be loaded in a consistent order. This makes rendered results + // stable across runs, otherwise replacement font picks are random + // and cause flakiness. + std::set<std::string> fonts; + struct dirent entry, *result; + while (readdir_r(fc_dir, &entry, &result) == 0 && result != NULL) { + fonts.insert(result->d_name); + } + for (const std::string& font : fonts) { + const std::string full_path = fontconfig_path + ("/" + font); + struct stat statbuf; + CHECK_EQ(0, stat(full_path.c_str(), &statbuf)) + << "Failed to stat " << full_path << ": " << strerror(errno); + if (S_ISREG(statbuf.st_mode)) { + // FcConfigAppFontAddFile will silently ignore non-fonts. + FcConfigAppFontAddFile( + config, reinterpret_cast<const FcChar8*>(full_path.c_str())); + } + } + closedir(fc_dir); + CHECK(FcConfigSetCurrent(config)); + + // Retrieve font from both of fontconfig's font sets for pre-loading. + std::set<std::string> font_files; + GetFontFileNames(FcConfigGetFonts(NULL, FcSetSystem), &font_files); + GetFontFileNames(FcConfigGetFonts(NULL, FcSetApplication), &font_files); + CHECK_GT(font_files.size(), 0u) + << "Font configuration doesn't contain any fonts!"; + + // Get freetype to load every font file we know about. This will cause the + // font files to get cached in memory. Once that's done we shouldn't have to + // access the file system for fonts at all. + FT_Library library; + FT_Init_FreeType(&library); + for (std::set<std::string>::const_iterator iter = font_files.begin(); + iter != font_files.end(); ++iter) { + FT_Face face; + CHECK_EQ(0, FT_New_Face(library, iter->c_str(), 0, &face)) + << "Failed to load font face: " << *iter; + FT_Done_Face(face); + } + FT_Done_FreeType(library); // Cached stuff will stick around... ? +} + +void ReleaseFonts() { + CHECK(g_config); + FcConfigDestroy(g_config); + FcFini(); +} + +} // namespace headless
diff --git a/headless/public/util/fontconfig.h b/headless/public/util/fontconfig.h new file mode 100644 index 0000000..2a504930 --- /dev/null +++ b/headless/public/util/fontconfig.h
@@ -0,0 +1,20 @@ +// Copyright 2017 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. + +#ifndef HEADLESS_PUBLIC_UTIL_FONTCONFIG_H_ +#define HEADLESS_PUBLIC_UTIL_FONTCONFIG_H_ + +namespace headless { + +// Initialize fontconfig by loading fonts from given path without following +// symlinks. This is a wrapper around FcInit from libfreetype bundled with +// Chromium modified to enable headless embedders to deploy in custom +// environments. +void InitFonts(const char* font_config_path); + +void ReleaseFonts(); + +} // namespace headless + +#endif // HEADLESS_PUBLIC_UTIL_FONTCONFIG_H_
diff --git a/ios/chrome/app/main_controller.mm b/ios/chrome/app/main_controller.mm index 6321c20..a45ae0a1 100644 --- a/ios/chrome/app/main_controller.mm +++ b/ios/chrome/app/main_controller.mm
@@ -18,7 +18,7 @@ #import "base/mac/bind_objc_block.h" #include "base/mac/bundle_locations.h" #include "base/mac/foundation_util.h" -#include "base/mac/objc_release_properties.h" +#include "base/mac/objc_property_releaser.h" #import "base/mac/scoped_nsobject.h" #include "base/macros.h" #include "base/path_service.h" @@ -132,8 +132,8 @@ #include "ios/public/provider/chrome/browser/signin/chrome_identity_service.h" #import "ios/public/provider/chrome/browser/user_feedback/user_feedback_provider.h" #import "ios/third_party/material_components_ios/src/components/Typography/src/MaterialTypography.h" -#import "ios/third_party/material_roboto_font_loader_ios/src/src/MDCTypographyAdditions/MDFRobotoFontLoader+MDCTypographyAdditions.h" #import "ios/third_party/material_roboto_font_loader_ios/src/src/MaterialRobotoFontLoader.h" +#import "ios/third_party/material_roboto_font_loader_ios/src/src/MDCTypographyAdditions/MDFRobotoFontLoader+MDCTypographyAdditions.h" #include "ios/web/net/request_tracker_factory_impl.h" #include "ios/web/net/request_tracker_impl.h" #include "ios/web/net/web_http_protocol_handler_delegate.h" @@ -331,6 +331,8 @@ // appropriate pref changes. base::scoped_nsobject<MemoryDebuggerManager> _memoryDebuggerManager; + base::mac::ObjCPropertyReleaser _propertyReleaser_MainController; + // Responsible for indexing chrome links (such as bookmarks, most likely...) // in system Spotlight index. base::scoped_nsobject<SpotlightManager> _spotlightManager; @@ -547,6 +549,7 @@ - (instancetype)init { if ((self = [super init])) { + _propertyReleaser_MainController.Init(self, [MainController class]); _startupTasks.reset([[StartupTasks alloc] init]); } return self; @@ -557,7 +560,6 @@ net::HTTPProtocolHandlerDelegate::SetInstance(nullptr); net::RequestTracker::SetRequestTrackerFactory(nullptr); [NSObject cancelPreviousPerformRequestsWithTarget:self]; - base::mac::ReleaseProperties(self); [super dealloc]; }
diff --git a/ios/chrome/browser/browser_state/BUILD.gn b/ios/chrome/browser/browser_state/BUILD.gn index 6fcca06..359a3ad 100644 --- a/ios/chrome/browser/browser_state/BUILD.gn +++ b/ios/chrome/browser/browser_state/BUILD.gn
@@ -106,6 +106,7 @@ "//ios/net", "//ios/public/provider/chrome/browser", "//ios/public/provider/chrome/browser/signin", + "//ios/shared/chrome/browser/ui/browser_list", "//ios/web", "//net", "//net:extras",
diff --git a/ios/chrome/browser/browser_state/browser_state_keyed_service_factories.mm b/ios/chrome/browser/browser_state/browser_state_keyed_service_factories.mm index a87f1b1..5faf7b4d1 100644 --- a/ios/chrome/browser/browser_state/browser_state_keyed_service_factories.mm +++ b/ios/chrome/browser/browser_state/browser_state_keyed_service_factories.mm
@@ -46,6 +46,7 @@ #include "ios/chrome/browser/translate/translate_accept_languages_factory.h" #include "ios/chrome/browser/undo/bookmark_undo_service_factory.h" #include "ios/chrome/browser/web_data_service_factory.h" +#include "ios/shared/chrome/browser/ui/browser_list/browser_list_session_service_factory.h" #if !defined(__has_feature) || !__has_feature(objc_arc) #error "This file requires ARC support." @@ -86,6 +87,7 @@ ios::WebDataServiceFactory::GetInstance(); ios::WebHistoryServiceFactory::GetInstance(); AuthenticationServiceFactory::GetInstance(); + BrowserListSessionServiceFactory::GetInstance(); DesktopPromotionSyncServiceFactory::GetInstance(); IOSChromeGCMProfileServiceFactory::GetInstance(); IOSChromeLargeIconCacheFactory::GetInstance();
diff --git a/ios/chrome/browser/browser_state/chrome_browser_state_impl_io_data.mm b/ios/chrome/browser/browser_state/chrome_browser_state_impl_io_data.mm index cbfc3772..0d0dfbf 100644 --- a/ios/chrome/browser/browser_state/chrome_browser_state_impl_io_data.mm +++ b/ios/chrome/browser/browser_state/chrome_browser_state_impl_io_data.mm
@@ -13,6 +13,7 @@ #include "base/logging.h" #include "base/memory/ptr_util.h" #include "base/sequenced_task_runner.h" +#include "base/task_scheduler/post_task.h" #include "base/threading/sequenced_worker_pool.h" #include "components/cookie_config/cookie_store_util.h" #include "components/net_log/chrome_net_log.h" @@ -86,11 +87,10 @@ io_data_->InitializeMetricsEnabledStateOnUIThread(); - base::SequencedWorkerPool* pool = web::WebThread::GetBlockingPool(); scoped_refptr<base::SequencedTaskRunner> db_task_runner = - pool->GetSequencedTaskRunnerWithShutdownBehavior( - pool->GetSequenceToken(), - base::SequencedWorkerPool::SKIP_ON_SHUTDOWN); + base::CreateSequencedTaskRunnerWithTraits( + {base::MayBlock(), base::TaskPriority::BACKGROUND, + base::TaskShutdownBehavior::SKIP_ON_SHUTDOWN}); } scoped_refptr<IOSChromeURLRequestContextGetter> @@ -260,8 +260,8 @@ scoped_refptr<net::SQLiteChannelIDStore> channel_id_db = new net::SQLiteChannelIDStore( lazy_params_->channel_id_path, - web::WebThread::GetBlockingPool()->GetSequencedTaskRunner( - web::WebThread::GetBlockingPool()->GetSequenceToken())); + base::CreateSequencedTaskRunnerWithTraits( + {base::MayBlock(), base::TaskPriority::BACKGROUND})); channel_id_service = new net::ChannelIDService( new net::DefaultChannelIDStore(channel_id_db.get())); }
diff --git a/ios/chrome/browser/browser_state/chrome_browser_state_io_data.cc b/ios/chrome/browser/browser_state/chrome_browser_state_io_data.cc index c7efc06..217d1b6 100644 --- a/ios/chrome/browser/browser_state/chrome_browser_state_io_data.cc +++ b/ios/chrome/browser/browser_state/chrome_browser_state_io_data.cc
@@ -22,7 +22,7 @@ #include "base/stl_util.h" #include "base/strings/string_number_conversions.h" #include "base/strings/string_util.h" -#include "base/threading/sequenced_worker_pool.h" +#include "base/task_scheduler/post_task.h" #include "base/threading/thread_task_runner_handle.h" #include "components/about_handler/about_protocol_handler.h" #include "components/content_settings/core/browser/content_settings_provider.h" @@ -356,11 +356,11 @@ std::move(profile_params_->proxy_config_service), true /* quick_check_enabled */); transport_security_state_.reset(new net::TransportSecurityState()); - base::SequencedWorkerPool* pool = web::WebThread::GetBlockingPool(); transport_security_persister_.reset(new net::TransportSecurityPersister( transport_security_state_.get(), profile_params_->path, - pool->GetSequencedTaskRunnerWithShutdownBehavior( - pool->GetSequenceToken(), base::SequencedWorkerPool::BLOCK_SHUTDOWN), + base::CreateSequencedTaskRunnerWithTraits( + {base::MayBlock(), base::TaskPriority::BACKGROUND, + base::TaskShutdownBehavior::BLOCK_SHUTDOWN}), IsOffTheRecord())); certificate_report_sender_ = @@ -400,8 +400,9 @@ bool set_protocol = job_factory->SetProtocolHandler( url::kFileScheme, base::MakeUnique<net::FileProtocolHandler>( - web::WebThread::GetBlockingPool()->GetTaskRunnerWithShutdownBehavior( - base::SequencedWorkerPool::SKIP_ON_SHUTDOWN))); + base::CreateTaskRunnerWithTraits( + {base::MayBlock(), base::TaskPriority::BACKGROUND, + base::TaskShutdownBehavior::SKIP_ON_SHUTDOWN}))); DCHECK(set_protocol); set_protocol = job_factory->SetProtocolHandler(
diff --git a/ios/chrome/browser/browser_state/chrome_browser_state_removal_controller.mm b/ios/chrome/browser/browser_state/chrome_browser_state_removal_controller.mm index ba86684..294b87dc 100644 --- a/ios/chrome/browser/browser_state/chrome_browser_state_removal_controller.mm +++ b/ios/chrome/browser/browser_state/chrome_browser_state_removal_controller.mm
@@ -12,6 +12,7 @@ #include "base/location.h" #include "base/mac/foundation_util.h" #include "base/strings/sys_string_conversions.h" +#include "base/task_scheduler/post_task.h" #include "components/prefs/pref_service.h" #include "google_apis/gaia/gaia_auth_util.h" #include "ios/chrome/browser/application_context.h" @@ -23,7 +24,6 @@ #include "ios/public/provider/chrome/browser/chrome_browser_provider.h" #import "ios/public/provider/chrome/browser/signin/chrome_identity.h" #include "ios/public/provider/chrome/browser/signin/chrome_identity_service.h" -#include "ios/web/public/web_thread.h" #if !defined(__has_feature) || !__has_feature(objc_arc) #error "This file requires ARC support." @@ -143,8 +143,9 @@ if (is_removing_browser_states) { SetHasBrowserStateBeenRemoved(true); - web::WebThread::PostBlockingPoolTask( - FROM_HERE, base::Bind(&NukeBrowserStates, browser_states_to_nuke)); + base::PostTaskWithTraits( + FROM_HERE, {base::MayBlock(), base::TaskPriority::BACKGROUND}, + base::BindOnce(&NukeBrowserStates, browser_states_to_nuke)); } }
diff --git a/ios/chrome/browser/content_suggestions/content_suggestions_mediator.mm b/ios/chrome/browser/content_suggestions/content_suggestions_mediator.mm index cbd7a4e0..9adb45bc 100644 --- a/ios/chrome/browser/content_suggestions/content_suggestions_mediator.mm +++ b/ios/chrome/browser/content_suggestions/content_suggestions_mediator.mm
@@ -5,6 +5,7 @@ #import "ios/chrome/browser/content_suggestions/content_suggestions_mediator.h" #include "base/mac/bind_objc_block.h" +#include "base/mac/foundation_util.h" #include "base/memory/ptr_util.h" #include "base/optional.h" #include "components/favicon/core/large_icon_service.h" @@ -17,15 +18,15 @@ #import "ios/chrome/browser/content_suggestions/content_suggestions_service_bridge_observer.h" #import "ios/chrome/browser/content_suggestions/mediator_util.h" #include "ios/chrome/browser/ntp_tiles/most_visited_sites_observer_bridge.h" -#import "ios/chrome/browser/ui/content_suggestions/content_suggestion.h" +#import "ios/chrome/browser/ui/content_suggestions/cells/content_suggestions_item.h" +#import "ios/chrome/browser/ui/content_suggestions/cells/content_suggestions_most_visited_item.h" +#import "ios/chrome/browser/ui/content_suggestions/cells/suggested_content.h" #import "ios/chrome/browser/ui/content_suggestions/content_suggestions_commands.h" #import "ios/chrome/browser/ui/content_suggestions/content_suggestions_data_sink.h" #import "ios/chrome/browser/ui/content_suggestions/content_suggestions_image_fetcher.h" #import "ios/chrome/browser/ui/content_suggestions/identifier/content_suggestion_identifier.h" #import "ios/chrome/browser/ui/content_suggestions/identifier/content_suggestions_section_information.h" #import "ios/chrome/browser/ui/favicon/favicon_attributes_provider.h" -#import "ios/chrome/browser/ui/reading_list/reading_list_collection_view_item.h" -#import "ios/chrome/browser/ui/reading_list/reading_list_utils.h" #include "ui/gfx/image/image.h" #if !defined(__has_feature) || !__has_feature(objc_arc) @@ -34,8 +35,10 @@ namespace { +using CSCollectionViewItem = CollectionViewItem<SuggestedContent>; + // Size of the favicon returned by the provider. -const CGFloat kDefaultFaviconSize = 16; +const CGFloat kDefaultFaviconSize = 48; // Maximum number of most visited tiles fetched. const NSInteger kMaxNumMostVisitedTiles = 8; @@ -70,21 +73,6 @@ @property(nonatomic, nullable, strong) FaviconAttributesProvider* attributesProvider; -// Converts the |suggestions| from |category| to ContentSuggestion and adds them -// to the |contentArray| if the category is available. -- (void)addSuggestions: - (const std::vector<ntp_snippets::ContentSuggestion>&)suggestions - fromCategory:(ntp_snippets::Category&)category - toArray:(NSMutableArray<ContentSuggestion*>*)contentArray; - -// Adds the section information for |category| in -// self.sectionInformationByCategory. -- (void)addSectionInformationForCategory:(ntp_snippets::Category)category; - -// Returns a CategoryWrapper acting as a key for this section info. -- (ContentSuggestionsCategoryWrapper*)categoryWrapperForSectionInfo: - (ContentSuggestionsSectionInformation*)sectionInfo; - @end @implementation ContentSuggestionsMediator @@ -138,22 +126,39 @@ #pragma mark - ContentSuggestionsDataSource -- (NSArray<ContentSuggestion*>*)allSuggestions { - NSMutableArray<ContentSuggestion*>* dataHolders = [NSMutableArray array]; +- (NSArray<ContentSuggestionsSectionInformation*>*)sectionsInfo { + NSMutableArray<ContentSuggestionsSectionInformation*>* sectionsInfo = + [NSMutableArray array]; - [self addMostVisitedToArray:dataHolders]; + if (!self.mostVisitedData.empty()) { + [sectionsInfo addObject:self.mostVisitedSectionInfo]; + } - [self addContentSuggestionsToArray:dataHolders]; + std::vector<ntp_snippets::Category> categories = + self.contentService->GetCategories(); - return dataHolders; + for (auto& category : categories) { + ContentSuggestionsCategoryWrapper* categoryWrapper = + [ContentSuggestionsCategoryWrapper wrapperWithCategory:category]; + if (!self.sectionInformationByCategory[categoryWrapper]) { + [self addSectionInformationForCategory:category]; + } + [sectionsInfo addObject:self.sectionInformationByCategory[categoryWrapper]]; + } + + return sectionsInfo; } -- (NSArray<ContentSuggestion*>*)suggestionsForSection: +- (NSArray<CSCollectionViewItem*>*)itemsForSectionInfo: (ContentSuggestionsSectionInformation*)sectionInfo { - NSMutableArray* convertedSuggestions = [NSMutableArray array]; + NSMutableArray<CSCollectionViewItem*>* convertedSuggestions = + [NSMutableArray array]; if (sectionInfo == self.mostVisitedSectionInfo) { - [self addMostVisitedToArray:convertedSuggestions]; + for (const ntp_tiles::NTPTile& tile : self.mostVisitedData) { + [convertedSuggestions + addObject:ConvertNTPTile(tile, self.mostVisitedSectionInfo)]; + } } else { ntp_snippets::Category category = [[self categoryWrapperForSectionInfo:sectionInfo] category]; @@ -162,7 +167,7 @@ self.contentService->GetSuggestionsForCategory(category); [self addSuggestions:suggestions fromCategory:category - toArray:convertedSuggestions]; + toItemArray:convertedSuggestions]; } return convertedSuggestions; @@ -177,14 +182,9 @@ fromSectionInfo: (ContentSuggestionsSectionInformation*)sectionInfo callback:(MoreSuggestionsFetched)callback { - if (![self isRelatedToContentSuggestionsService:sectionInfo]) + if (![self isRelatedToContentSuggestionsService:sectionInfo]) { + callback(nil); return; - - std::set<std::string> known_suggestion_ids; - for (ContentSuggestionIdentifier* identifier in knownSuggestions) { - if (identifier.sectionInfo != sectionInfo) - continue; - known_suggestion_ids.insert(identifier.IDInSection); } ContentSuggestionsCategoryWrapper* wrapper = @@ -194,13 +194,17 @@ self.contentService->GetCategoryInfo([wrapper category]); if (!categoryInfo) { + callback(nil); return; } + switch (categoryInfo->additional_action()) { case ntp_snippets::ContentSuggestionsAdditionalAction::NONE: + callback(nil); return; case ntp_snippets::ContentSuggestionsAdditionalAction::VIEW_ALL: + callback(nil); if ([wrapper category].IsKnownCategory( ntp_snippets::KnownCategories::READING_LIST)) { [self.commandHandler openReadingList]; @@ -208,6 +212,13 @@ break; case ntp_snippets::ContentSuggestionsAdditionalAction::FETCH: { + std::set<std::string> known_suggestion_ids; + for (ContentSuggestionIdentifier* identifier in knownSuggestions) { + if (identifier.sectionInfo != sectionInfo) + continue; + known_suggestion_ids.insert(identifier.IDInSection); + } + __weak ContentSuggestionsMediator* weakSelf = self; ntp_snippets::FetchDoneCallback serviceCallback = base::Bind( &BindWrapper, @@ -227,17 +238,40 @@ } } -- (void)fetchFaviconAttributesForURL:(const GURL&)URL - completion:(void (^)(FaviconAttributes*))completion { - [self.attributesProvider fetchFaviconAttributesForURL:URL +- (void)fetchFaviconAttributesForItem:(CSCollectionViewItem*)item + completion:(void (^)(FaviconAttributes*))completion { + ContentSuggestionsSectionInformation* sectionInfo = + item.suggestionIdentifier.sectionInfo; + GURL url; + if (![self isRelatedToContentSuggestionsService:sectionInfo]) { + ContentSuggestionsMostVisitedItem* mostVisited = + base::mac::ObjCCast<ContentSuggestionsMostVisitedItem>(item); + url = mostVisited.URL; + } else { + ContentSuggestionsItem* suggestionItem = + base::mac::ObjCCast<ContentSuggestionsItem>(item); + url = suggestionItem.URL; + } + [self.attributesProvider fetchFaviconAttributesForURL:url completion:completion]; } -- (void)fetchFaviconImageForSuggestion:(ContentSuggestionIdentifier*)suggestion - completion:(void (^)(UIImage*))completion { - if (!completion) +- (void)fetchFaviconImageForItem:(CSCollectionViewItem*)item + completion:(void (^)(UIImage*))completion { + ContentSuggestionsSectionInformation* sectionInfo = + item.suggestionIdentifier.sectionInfo; + if (![self isRelatedToContentSuggestionsService:sectionInfo]) { return; - + } + ContentSuggestionsItem* suggestionItem = + base::mac::ObjCCast<ContentSuggestionsItem>(item); + ntp_snippets::Category category = + [[self categoryWrapperForSectionInfo:sectionInfo] category]; + if (!category.IsKnownCategory(ntp_snippets::KnownCategories::ARTICLES)) { + // TODO(crbug.com/721266): remove this guard once the choice to download the + // favicon from the google server is done in the provider. + return; + } void (^imageCallback)(const gfx::Image&) = ^(const gfx::Image& image) { if (!image.IsEmpty()) { completion([image.ToUIImage() copy]); @@ -246,9 +280,7 @@ ntp_snippets::ContentSuggestion::ID identifier = ntp_snippets::ContentSuggestion::ID( - [[self categoryWrapperForSectionInfo:suggestion.sectionInfo] - category], - suggestion.IDInSection); + category, suggestionItem.suggestionIdentifier.IDInSection); self.contentService->FetchSuggestionFavicon( identifier, /* minimum_size_in_pixel = */ 1, kDefaultFaviconSize, base::BindBlockArc(imageCallback)); @@ -346,10 +378,12 @@ #pragma mark - Private +// Converts the |suggestions| from |category| to CSCollectionViewItem and adds +// them to the |contentArray| if the category is available. - (void)addSuggestions: (const std::vector<ntp_snippets::ContentSuggestion>&)suggestions fromCategory:(ntp_snippets::Category&)category - toArray:(NSMutableArray<ContentSuggestion*>*)contentArray { + toItemArray:(NSMutableArray<CSCollectionViewItem*>*)itemArray { if (!ntp_snippets::IsCategoryStatusAvailable( self.contentService->GetCategoryStatus(category))) { return; @@ -360,32 +394,18 @@ if (!self.sectionInformationByCategory[categoryWrapper]) { [self addSectionInformationForCategory:category]; } - + ContentSuggestionsSectionInformation* sectionInfo = + self.sectionInformationByCategory[categoryWrapper]; for (auto& contentSuggestion : suggestions) { - ContentSuggestion* suggestion = ConvertContentSuggestion(contentSuggestion); + CSCollectionViewItem* suggestion = + ConvertSuggestion(contentSuggestion, sectionInfo, category); - suggestion.type = TypeForCategory(category); - - suggestion.suggestionIdentifier.sectionInfo = - self.sectionInformationByCategory[categoryWrapper]; - - if (category.IsKnownCategory(ntp_snippets::KnownCategories::READING_LIST)) { - suggestion.availableOffline = - contentSuggestion.reading_list_suggestion_extra()->distilled; - } - - [contentArray addObject:suggestion]; - } - - if (suggestions.size() == 0) { - ContentSuggestion* suggestion = EmptySuggestion(); - suggestion.suggestionIdentifier.sectionInfo = - self.sectionInformationByCategory[categoryWrapper]; - - [contentArray addObject:suggestion]; + [itemArray addObject:suggestion]; } } +// Adds the section information for |category| in +// self.sectionInformationByCategory. - (void)addSectionInformationForCategory:(ntp_snippets::Category)category { base::Optional<ntp_snippets::CategoryInfo> categoryInfo = self.contentService->GetCategoryInfo(category); @@ -397,6 +417,7 @@ wrapperWithCategory:category]] = sectionInfo; } +// Returns a CategoryWrapper acting as a key for this section info. - (ContentSuggestionsCategoryWrapper*)categoryWrapperForSectionInfo: (ContentSuggestionsSectionInformation*)sectionInfo { return [[self.sectionInformationByCategory allKeysForObject:sectionInfo] @@ -409,45 +430,15 @@ (const std::vector<ntp_snippets::ContentSuggestion>&)suggestions withStatusCode:(ntp_snippets::Status)statusCode callback:(MoreSuggestionsFetched)callback { + NSMutableArray<CSCollectionViewItem*>* contentSuggestions = nil; if (statusCode.IsSuccess() && !suggestions.empty() && callback) { - NSMutableArray<ContentSuggestion*>* contentSuggestions = - [NSMutableArray array]; + contentSuggestions = [NSMutableArray array]; ntp_snippets::Category category = suggestions[0].id().category(); [self addSuggestions:suggestions fromCategory:category - toArray:contentSuggestions]; - callback(contentSuggestions); + toItemArray:contentSuggestions]; } -} - -// Adds all the suggestions from the |contentService| to |suggestions|. -- (void)addContentSuggestionsToArray: - (NSMutableArray<ContentSuggestion*>*)arrayToFill { - std::vector<ntp_snippets::Category> categories = - self.contentService->GetCategories(); - - for (auto& category : categories) { - const std::vector<ntp_snippets::ContentSuggestion>& suggestions = - self.contentService->GetSuggestionsForCategory(category); - [self addSuggestions:suggestions fromCategory:category toArray:arrayToFill]; - } -} - -// Adds all the suggestions for the |mostVisitedData| to |suggestions|. -- (void)addMostVisitedToArray:(NSMutableArray<ContentSuggestion*>*)arrayToFill { - if (self.mostVisitedData.empty()) { - ContentSuggestion* suggestion = EmptySuggestion(); - suggestion.suggestionIdentifier.sectionInfo = self.mostVisitedSectionInfo; - [arrayToFill addObject:suggestion]; - - return; - } - - for (const ntp_tiles::NTPTile& tile : self.mostVisitedData) { - ContentSuggestion* suggestion = ConvertNTPTile(tile); - suggestion.suggestionIdentifier.sectionInfo = self.mostVisitedSectionInfo; - [arrayToFill addObject:suggestion]; - } + callback(contentSuggestions); } // Returns whether the |sectionInfo| is associated with a category from the
diff --git a/ios/chrome/browser/content_suggestions/mediator_util.h b/ios/chrome/browser/content_suggestions/mediator_util.h index 1651ca97..9e06bfa 100644 --- a/ios/chrome/browser/content_suggestions/mediator_util.h +++ b/ios/chrome/browser/content_suggestions/mediator_util.h
@@ -11,15 +11,14 @@ #include "components/ntp_snippets/content_suggestion.h" #include "components/ntp_snippets/status.h" #include "components/ntp_tiles/ntp_tile.h" -#import "ios/chrome/browser/ui/content_suggestions/content_suggestion.h" +#import "ios/chrome/browser/ui/content_suggestions/cells/suggested_content.h" #import "ios/chrome/browser/ui/content_suggestions/identifier/content_suggestions_section_information.h" namespace ntp_snippets { -class ContentSuggestion; class Category; -class CategoryInfo; } +@class CollectionViewItem; @class ContentSuggestionsCategoryWrapper; // TODO(crbug.com/701275): Once base::BindBlock supports the move semantics, @@ -32,21 +31,15 @@ ntp_snippets::Status status_code, std::vector<ntp_snippets::ContentSuggestion> suggestions); -// Returns the Type for this |category|. -ContentSuggestionType TypeForCategory(ntp_snippets::Category category); - // Returns the section ID for this |category|. ContentSuggestionsSectionID SectionIDForCategory( ntp_snippets::Category category); -// Returns the section layout corresponding to the category |layout|. -ContentSuggestionsSectionLayout SectionLayoutForLayout( - ntp_snippets::ContentSuggestionsCardLayout layout); - -// Converts a ntp_snippets::ContentSuggestion to an Objective-C -// ContentSuggestion. -ContentSuggestion* ConvertContentSuggestion( - const ntp_snippets::ContentSuggestion& contentSuggestion); +// Converts a ntp_snippets::ContentSuggestion to a CollectionViewItem. +CollectionViewItem<SuggestedContent>* ConvertSuggestion( + const ntp_snippets::ContentSuggestion& contentSuggestion, + ContentSuggestionsSectionInformation* sectionInfo, + ntp_snippets::Category category); // Returns a SectionInformation for a |category|, filled with the // |categoryInfo|. @@ -60,17 +53,16 @@ ContentSuggestionsCategoryWrapper* category, const std::string& id_in_category); -// Creates and returns an empty suggestion. -ContentSuggestion* EmptySuggestion(); - // Creates and returns a SectionInfo for the Most Visited section. ContentSuggestionsSectionInformation* MostVisitedSectionInformation(); // Records the page impression of the ntp tiles. void RecordPageImpression(const std::vector<ntp_tiles::NTPTile>& mostVisited); -// Converts a ntp_snippets::ContentSuggestion to an Objective-C -// ContentSuggestion. -ContentSuggestion* ConvertNTPTile(const ntp_tiles::NTPTile& tile); +// Converts a ntp_snippets::ContentSuggestion to an adapted CollectionViewItem +// with a |sectionInfo|. +CollectionViewItem<SuggestedContent>* ConvertNTPTile( + const ntp_tiles::NTPTile& tile, + ContentSuggestionsSectionInformation* sectionInfo); #endif // IOS_CHROME_BROWSER_CONTENT_SUGGESTIONS_MEDIATOR_UTIL_H_
diff --git a/ios/chrome/browser/content_suggestions/mediator_util.mm b/ios/chrome/browser/content_suggestions/mediator_util.mm index d4ea2f9d..5b428ba 100644 --- a/ios/chrome/browser/content_suggestions/mediator_util.mm +++ b/ios/chrome/browser/content_suggestions/mediator_util.mm
@@ -10,6 +10,10 @@ #include "components/rappor/rappor_service_impl.h" #include "ios/chrome/browser/application_context.h" #import "ios/chrome/browser/content_suggestions/content_suggestions_category_wrapper.h" +#import "ios/chrome/browser/ui/collection_view/cells/collection_view_text_item.h" +#import "ios/chrome/browser/ui/content_suggestions/cells/content_suggestions_item.h" +#import "ios/chrome/browser/ui/content_suggestions/cells/content_suggestions_most_visited_item.h" +#import "ios/chrome/browser/ui/content_suggestions/cells/suggested_content.h" #import "ios/chrome/browser/ui/content_suggestions/identifier/content_suggestion_identifier.h" #include "ios/chrome/grit/ios_strings.h" #include "ui/base/l10n/l10n_util_mac.h" @@ -29,15 +33,6 @@ } } -ContentSuggestionType TypeForCategory(ntp_snippets::Category category) { - if (category.IsKnownCategory(ntp_snippets::KnownCategories::ARTICLES)) - return ContentSuggestionTypeArticle; - if (category.IsKnownCategory(ntp_snippets::KnownCategories::READING_LIST)) - return ContentSuggestionTypeReadingList; - - return ContentSuggestionTypeEmpty; -} - ContentSuggestionsSectionID SectionIDForCategory( ntp_snippets::Category category) { if (category.IsKnownCategory(ntp_snippets::KnownCategories::ARTICLES)) @@ -48,19 +43,15 @@ return ContentSuggestionsSectionUnknown; } -ContentSuggestionsSectionLayout SectionLayoutForLayout( - ntp_snippets::ContentSuggestionsCardLayout layout) { - // For now, only cards are relevant. - return ContentSuggestionsSectionLayoutCard; -} - -ContentSuggestion* ConvertContentSuggestion( - const ntp_snippets::ContentSuggestion& contentSuggestion) { - ContentSuggestion* suggestion = [[ContentSuggestion alloc] init]; - - suggestion.title = base::SysUTF16ToNSString(contentSuggestion.title()); - suggestion.text = base::SysUTF16ToNSString(contentSuggestion.snippet_text()); - suggestion.url = contentSuggestion.url(); +CollectionViewItem<SuggestedContent>* ConvertSuggestion( + const ntp_snippets::ContentSuggestion& contentSuggestion, + ContentSuggestionsSectionInformation* sectionInfo, + ntp_snippets::Category category) { + ContentSuggestionsItem* suggestion = [[ContentSuggestionsItem alloc] + initWithType:0 + title:base::SysUTF16ToNSString(contentSuggestion.title()) + subtitle:base::SysUTF16ToNSString(contentSuggestion.snippet_text()) + url:contentSuggestion.url()]; suggestion.publisher = base::SysUTF16ToNSString(contentSuggestion.publisher_name()); @@ -69,6 +60,15 @@ suggestion.suggestionIdentifier = [[ContentSuggestionIdentifier alloc] init]; suggestion.suggestionIdentifier.IDInSection = contentSuggestion.id().id_within_category(); + suggestion.suggestionIdentifier.sectionInfo = sectionInfo; + + if (category.IsKnownCategory(ntp_snippets::KnownCategories::READING_LIST)) { + suggestion.availableOffline = + contentSuggestion.reading_list_suggestion_extra()->distilled; + } + if (category.IsKnownCategory(ntp_snippets::KnownCategories::ARTICLES)) { + suggestion.hasImage = YES; + } return suggestion; } @@ -80,7 +80,7 @@ [[ContentSuggestionsSectionInformation alloc] initWithSectionID:SectionIDForCategory(category)]; if (categoryInfo) { - sectionInfo.layout = SectionLayoutForLayout(categoryInfo->card_layout()); + sectionInfo.layout = ContentSuggestionsSectionLayoutCard; sectionInfo.showIfEmpty = categoryInfo->show_if_empty(); sectionInfo.emptyText = base::SysUTF16ToNSString(categoryInfo->no_suggestions_message()); @@ -100,14 +100,6 @@ return ntp_snippets::ContentSuggestion::ID(category.category, id_in_category); } -ContentSuggestion* EmptySuggestion() { - ContentSuggestion* suggestion = [[ContentSuggestion alloc] init]; - suggestion.type = ContentSuggestionTypeEmpty; - suggestion.suggestionIdentifier = [[ContentSuggestionIdentifier alloc] init]; - - return suggestion; -} - ContentSuggestionsSectionInformation* MostVisitedSectionInformation() { ContentSuggestionsSectionInformation* sectionInfo = [[ContentSuggestionsSectionInformation alloc] @@ -130,15 +122,18 @@ tiles, GetApplicationContext()->GetRapporServiceImpl()); } -ContentSuggestion* ConvertNTPTile(const ntp_tiles::NTPTile& tile) { - ContentSuggestion* suggestion = [[ContentSuggestion alloc] init]; +CollectionViewItem<SuggestedContent>* ConvertNTPTile( + const ntp_tiles::NTPTile& tile, + ContentSuggestionsSectionInformation* sectionInfo) { + ContentSuggestionsMostVisitedItem* suggestion = + [[ContentSuggestionsMostVisitedItem alloc] initWithType:0]; suggestion.title = base::SysUTF16ToNSString(tile.title); - suggestion.url = tile.url; - suggestion.type = ContentSuggestionTypeMostVisited; + suggestion.URL = tile.url; suggestion.suggestionIdentifier = [[ContentSuggestionIdentifier alloc] init]; suggestion.suggestionIdentifier.IDInSection = tile.url.spec(); + suggestion.suggestionIdentifier.sectionInfo = sectionInfo; return suggestion; }
diff --git a/ios/chrome/browser/passwords/update_password_infobar_controller.mm b/ios/chrome/browser/passwords/update_password_infobar_controller.mm index 22d6a445..656b3bb 100644 --- a/ios/chrome/browser/passwords/update_password_infobar_controller.mm +++ b/ios/chrome/browser/passwords/update_password_infobar_controller.mm
@@ -4,7 +4,7 @@ #import "ios/chrome/browser/passwords/update_password_infobar_controller.h" -#include "base/mac/objc_release_properties.h" +#import "base/mac/objc_property_releaser.h" #include "base/strings/string_util.h" #include "base/strings/sys_string_conversions.h" #include "ios/chrome/browser/infobars/confirm_infobar_controller+protected.h" @@ -19,6 +19,8 @@ } @interface UpdatePasswordInfoBarController ()<SelectorCoordinatorDelegate> { + base::mac::ObjCPropertyReleaser + _propertyReleaser_UpdatePasswordInfoBarController; IOSChromeUpdatePasswordInfoBarDelegate* _delegate; } @property(nonatomic, retain) SelectorCoordinator* selectorCoordinator; @@ -28,9 +30,13 @@ @synthesize selectorCoordinator = _selectorCoordinator; -- (void)dealloc { - base::mac::ReleaseProperties(self); - [super dealloc]; +- (instancetype)initWithDelegate:(InfoBarViewDelegate*)delegate { + self = [super initWithDelegate:delegate]; + if (self) { + _propertyReleaser_UpdatePasswordInfoBarController.Init( + self, [UpdatePasswordInfoBarController class]); + } + return self; } - (InfoBarView*)viewForDelegate:
diff --git a/ios/chrome/browser/snapshots/snapshot_cache.mm b/ios/chrome/browser/snapshots/snapshot_cache.mm index a2174949..7fb720d 100644 --- a/ios/chrome/browser/snapshots/snapshot_cache.mm +++ b/ios/chrome/browser/snapshots/snapshot_cache.mm
@@ -13,7 +13,7 @@ #include "base/location.h" #include "base/logging.h" #include "base/mac/bind_objc_block.h" -#include "base/mac/objc_release_properties.h" +#include "base/mac/objc_property_releaser.h" #include "base/mac/scoped_cftyperef.h" #include "base/mac/scoped_nsobject.h" #include "base/strings/sys_string_conversions.h" @@ -157,6 +157,8 @@ // be requested to be saved to disk when the application is backgrounded. base::scoped_nsobject<NSString> backgroundingImageSessionId_; base::scoped_nsobject<UIImage> backgroundingColorImage_; + + base::mac::ObjCPropertyReleaser propertyReleaser_SnapshotCache_; } @synthesize pinnedIDs = pinnedIDs_; @@ -169,6 +171,8 @@ - (id)init { if ((self = [super init])) { DCHECK_CURRENTLY_ON(web::WebThread::UI); + propertyReleaser_SnapshotCache_.Init(self, [SnapshotCache class]); + if ([self usesLRUCache]) { lruCache_.reset( [[LRUCache alloc] initWithCacheSize:kLRUCacheMaxCapacity]); @@ -208,7 +212,6 @@ removeObserver:self name:UIApplicationDidBecomeActiveNotification object:nil]; - base::mac::ReleaseProperties(self); [super dealloc]; }
diff --git a/ios/chrome/browser/ui/authentication/authentication_flow.mm b/ios/chrome/browser/ui/authentication/authentication_flow.mm index f00b3dc..ca6c1dd 100644 --- a/ios/chrome/browser/ui/authentication/authentication_flow.mm +++ b/ios/chrome/browser/ui/authentication/authentication_flow.mm
@@ -6,7 +6,7 @@ #include "base/ios/weak_nsobject.h" #include "base/logging.h" -#include "base/mac/objc_release_properties.h" +#include "base/mac/objc_property_releaser.h" #include "base/mac/scoped_block.h" #include "base/mac/scoped_nsobject.h" #include "ios/chrome/browser/browser_state/chrome_browser_state.h" @@ -101,6 +101,8 @@ // is in progress to ensure it outlives any attempt to destroy it in // |_signInCompletion|. base::scoped_nsobject<AuthenticationFlow> _selfRetainer; + + base::mac::ObjCPropertyReleaser _propertyReleaser_AuthenticationFlow; } @synthesize handlingError = _handlingError; @@ -122,15 +124,11 @@ _postSignInAction = postSignInAction; _presentingViewController.reset([presentingViewController retain]); _state = BEGIN; + _propertyReleaser_AuthenticationFlow.Init(self, [AuthenticationFlow class]); } return self; } -- (void)dealloc { - base::mac::ReleaseProperties(self); - [super dealloc]; -} - - (void)startSignInWithCompletion:(CompletionCallback)completion { DCHECK_EQ(BEGIN, _state); DCHECK(!_signInCompletion);
diff --git a/ios/chrome/browser/ui/content_suggestions/BUILD.gn b/ios/chrome/browser/ui/content_suggestions/BUILD.gn index 7cacefbe..c4d50084 100644 --- a/ios/chrome/browser/ui/content_suggestions/BUILD.gn +++ b/ios/chrome/browser/ui/content_suggestions/BUILD.gn
@@ -4,8 +4,6 @@ source_set("content_suggestions") { sources = [ - "content_suggestion.h", - "content_suggestion.mm", "content_suggestions_collection_updater.h", "content_suggestions_collection_updater.mm", "content_suggestions_collection_utils.h", @@ -50,6 +48,7 @@ "//base", "//ios/chrome/browser/ui", "//ios/chrome/browser/ui/collection_view", + "//ios/chrome/browser/ui/content_suggestions/cells", "//ios/chrome/browser/ui/content_suggestions/identifier", "//ios/chrome/test/base", "//testing/gtest",
diff --git a/ios/chrome/browser/ui/content_suggestions/cells/BUILD.gn b/ios/chrome/browser/ui/content_suggestions/cells/BUILD.gn index a42fb2a..2b23598 100644 --- a/ios/chrome/browser/ui/content_suggestions/cells/BUILD.gn +++ b/ios/chrome/browser/ui/content_suggestions/cells/BUILD.gn
@@ -12,6 +12,7 @@ "content_suggestions_most_visited_item.mm", "content_suggestions_text_item.h", "content_suggestions_text_item.mm", + "suggested_content.h", ] deps = [ "//base",
diff --git a/ios/chrome/browser/ui/content_suggestions/cells/content_suggestions_item.h b/ios/chrome/browser/ui/content_suggestions/cells/content_suggestions_item.h index a27b4823..72a12b1 100644 --- a/ios/chrome/browser/ui/content_suggestions/cells/content_suggestions_item.h +++ b/ios/chrome/browser/ui/content_suggestions/cells/content_suggestions_item.h
@@ -6,7 +6,7 @@ #define IOS_CHROME_BROWSER_UI_CONTENT_SUGGESTIONS_CELLS_CONTENT_SUGGESTIONS_ITEM_H_ #import "ios/chrome/browser/ui/collection_view/cells/collection_view_item.h" -#import "ios/chrome/browser/ui/content_suggestions/identifier/content_suggestion_identifier.h" +#import "ios/chrome/browser/ui/content_suggestions/cells/suggested_content.h" #import "ios/third_party/material_components_ios/src/components/CollectionCells/src/MaterialCollectionCells.h" namespace base { @@ -18,36 +18,22 @@ @class FaviconViewNew; class GURL; -// Delegate for a ContentSuggestionsItem. -@protocol ContentSuggestionsItemDelegate - -// Loads the image associated with this item. -- (void)loadImageForSuggestionItem:(ContentSuggestionsItem*)suggestionItem; - -@end - // Item for an article in the suggestions. -@interface ContentSuggestionsItem - : CollectionViewItem<ContentSuggestionIdentification> +@interface ContentSuggestionsItem : CollectionViewItem<SuggestedContent> // Initialize an article with a |title|, a |subtitle|, an |image| and the |url| // to the full article. |type| is the type of the item. - (instancetype)initWithType:(NSInteger)type title:(NSString*)title subtitle:(NSString*)subtitle - delegate:(id<ContentSuggestionsItemDelegate>)delegate url:(const GURL&)url NS_DESIGNATED_INITIALIZER; - (instancetype)initWithType:(NSInteger)type NS_UNAVAILABLE; @property(nonatomic, copy, readonly) NSString* title; -@property(nonatomic, strong) UIImage* image; @property(nonatomic, readonly, assign) GURL URL; @property(nonatomic, copy) NSString* publisher; @property(nonatomic, assign) base::Time publishDate; -@property(nonatomic, weak) id<ContentSuggestionsItemDelegate> delegate; -// Attributes for favicon. -@property(nonatomic, strong) FaviconAttributes* attributes; // Whether the suggestion has an image associated. @property(nonatomic, assign) BOOL hasImage; // Whether the suggestion is available offline. If YES, an icon is displayed.
diff --git a/ios/chrome/browser/ui/content_suggestions/cells/content_suggestions_item.mm b/ios/chrome/browser/ui/content_suggestions/cells/content_suggestions_item.mm index ffa7778..985d582 100644 --- a/ios/chrome/browser/ui/content_suggestions/cells/content_suggestions_item.mm +++ b/ios/chrome/browser/ui/content_suggestions/cells/content_suggestions_item.mm
@@ -6,6 +6,7 @@ #include "base/time/time.h" #import "ios/chrome/browser/ui/colors/MDCPalette+CrAdditions.h" +#import "ios/chrome/browser/ui/content_suggestions/identifier/content_suggestion_identifier.h" #import "ios/chrome/browser/ui/favicon/favicon_attributes.h" #import "ios/chrome/browser/ui/favicon/favicon_view.h" #import "ios/chrome/browser/ui/uikit_ui_util.h" @@ -74,7 +75,6 @@ - (instancetype)initWithType:(NSInteger)type title:(NSString*)title subtitle:(NSString*)subtitle - delegate:(id<ContentSuggestionsItemDelegate>)delegate url:(const GURL&)url { self = [super initWithType:type]; if (self) { @@ -82,7 +82,6 @@ _title = [title copy]; _subtitle = [subtitle copy]; _URL = url; - _delegate = delegate; } return self; } @@ -92,7 +91,7 @@ if (self.hasImage && !self.imageFetched) { self.imageFetched = YES; // Fetch the image. During the fetch the cell's image should still be set. - [self.delegate loadImageForSuggestionItem:self]; + [self.delegate loadImageForSuggestedItem:self]; } [cell.faviconView configureWithAttributes:self.attributes]; cell.titleLabel.text = self.title;
diff --git a/ios/chrome/browser/ui/content_suggestions/cells/content_suggestions_item_unittest.mm b/ios/chrome/browser/ui/content_suggestions/cells/content_suggestions_item_unittest.mm index 70b6647..807db2fb 100644 --- a/ios/chrome/browser/ui/content_suggestions/cells/content_suggestions_item_unittest.mm +++ b/ios/chrome/browser/ui/content_suggestions/cells/content_suggestions_item_unittest.mm
@@ -25,18 +25,18 @@ GURL url = GURL("http://chromium.org"); NSString* publisher = @"publisherName"; base::Time publishTime = base::Time::Now(); - id delegateMock = OCMProtocolMock(@protocol(ContentSuggestionsItemDelegate)); + id delegateMock = OCMProtocolMock(@protocol(SuggestedContentDelegate)); ContentSuggestionsItem* item = [[ContentSuggestionsItem alloc] initWithType:0 title:title subtitle:subtitle - delegate:delegateMock url:url]; + item.delegate = delegateMock; item.hasImage = YES; item.publisher = publisher; item.publishDate = publishTime; item.availableOffline = YES; - OCMExpect([delegateMock loadImageForSuggestionItem:item]); + OCMExpect([delegateMock loadImageForSuggestedItem:item]); ContentSuggestionsCell* cell = [[[item cellClass] alloc] init]; ASSERT_EQ([ContentSuggestionsCell class], [cell class]); ASSERT_EQ(url, item.URL); @@ -64,25 +64,24 @@ NSString* title = @"testTitle"; NSString* subtitle = @"testSubtitle"; GURL url = GURL("http://chromium.org"); - id niceDelegateMock = - OCMProtocolMock(@protocol(ContentSuggestionsItemDelegate)); + id niceDelegateMock = OCMProtocolMock(@protocol(SuggestedContentDelegate)); ContentSuggestionsItem* item = [[ContentSuggestionsItem alloc] initWithType:0 title:title subtitle:subtitle - delegate:niceDelegateMock url:url]; + item.delegate = niceDelegateMock; item.hasImage = YES; item.image = [[UIImage alloc] init]; - OCMExpect([niceDelegateMock loadImageForSuggestionItem:item]); + OCMExpect([niceDelegateMock loadImageForSuggestedItem:item]); ContentSuggestionsCell* cell = [[[item cellClass] alloc] init]; ASSERT_NE(nil, item.image); [item configureCell:cell]; ASSERT_OCMOCK_VERIFY(niceDelegateMock); id strictDelegateMock = - OCMStrictProtocolMock(@protocol(ContentSuggestionsItemDelegate)); + OCMStrictProtocolMock(@protocol(SuggestedContentDelegate)); item.delegate = strictDelegateMock; id cellMock = OCMPartialMock(cell); OCMExpect([cellMock setContentImage:item.image]); @@ -103,14 +102,13 @@ NSString* subtitle = @"testSubtitle"; GURL url = GURL("http://chromium.org"); // Strict mock. Raise exception if the load method is called. - id delegateMock = - OCMStrictProtocolMock(@protocol(ContentSuggestionsItemDelegate)); + id delegateMock = OCMStrictProtocolMock(@protocol(SuggestedContentDelegate)); ContentSuggestionsItem* item = [[ContentSuggestionsItem alloc] initWithType:0 title:title subtitle:subtitle - delegate:delegateMock url:url]; + item.delegate = delegateMock; item.hasImage = NO; ContentSuggestionsCell* cell = [[[item cellClass] alloc] init];
diff --git a/ios/chrome/browser/ui/content_suggestions/cells/content_suggestions_most_visited_item.h b/ios/chrome/browser/ui/content_suggestions/cells/content_suggestions_most_visited_item.h index f2f7f974..5bf00530 100644 --- a/ios/chrome/browser/ui/content_suggestions/cells/content_suggestions_most_visited_item.h +++ b/ios/chrome/browser/ui/content_suggestions/cells/content_suggestions_most_visited_item.h
@@ -6,15 +6,16 @@ #define IOS_CHROME_BROWSER_UI_CONTENT_SUGGESTIONS_CELLS_CONTENT_SUGGESTIONS_MOST_VISITED_ITEM_H_ #import "ios/chrome/browser/ui/collection_view/cells/collection_view_item.h" -#import "ios/chrome/browser/ui/content_suggestions/identifier/content_suggestion_identifier.h" +#import "ios/chrome/browser/ui/content_suggestions/cells/suggested_content.h" #import "ios/third_party/material_components_ios/src/components/CollectionCells/src/MaterialCollectionCells.h" @class FaviconAttributes; @class FaviconViewNew; +class GURL; // Item containing a Most Visited suggestion. @interface ContentSuggestionsMostVisitedItem - : CollectionViewItem<ContentSuggestionIdentification> + : CollectionViewItem<SuggestedContent> // Attributes to configure the favicon view. @property(nonatomic, strong, nonnull) FaviconAttributes* attributes; @@ -22,6 +23,8 @@ // Text for the title and the accessibility label of the cell. @property(nonatomic, copy, nonnull) NSString* title; +@property(nonatomic, assign) GURL URL; + @end // Associated cell to display a Most Visited tile based on the suggestion.
diff --git a/ios/chrome/browser/ui/content_suggestions/cells/content_suggestions_most_visited_item.mm b/ios/chrome/browser/ui/content_suggestions/cells/content_suggestions_most_visited_item.mm index 0e121d4..ab0c47f 100644 --- a/ios/chrome/browser/ui/content_suggestions/cells/content_suggestions_most_visited_item.mm +++ b/ios/chrome/browser/ui/content_suggestions/cells/content_suggestions_most_visited_item.mm
@@ -4,10 +4,12 @@ #import "ios/chrome/browser/ui/content_suggestions/cells/content_suggestions_most_visited_item.h" +#import "ios/chrome/browser/ui/content_suggestions/identifier/content_suggestion_identifier.h" #import "ios/chrome/browser/ui/favicon/favicon_attributes.h" #import "ios/chrome/browser/ui/favicon/favicon_view.h" #import "ios/chrome/browser/ui/uikit_ui_util.h" #import "ios/third_party/material_components_ios/src/components/Typography/src/MaterialTypography.h" +#include "url/gurl.h" #if !defined(__has_feature) || !__has_feature(objc_arc) #error "This file requires ARC support." @@ -30,6 +32,9 @@ @synthesize suggestionIdentifier = _suggestionIdentifier; @synthesize attributes = _attributes; @synthesize title = _title; +@synthesize URL = _URL; +@synthesize delegate = _delegate; +@synthesize image = _image; - (instancetype)initWithType:(NSInteger)type { self = [super initWithType:type];
diff --git a/ios/chrome/browser/ui/content_suggestions/cells/content_suggestions_text_item.h b/ios/chrome/browser/ui/content_suggestions/cells/content_suggestions_text_item.h index f76b031c..f2b403f 100644 --- a/ios/chrome/browser/ui/content_suggestions/cells/content_suggestions_text_item.h +++ b/ios/chrome/browser/ui/content_suggestions/cells/content_suggestions_text_item.h
@@ -8,11 +8,10 @@ #import <UIKit/UIKit.h> #import "ios/chrome/browser/ui/collection_view/cells/collection_view_item.h" -#import "ios/chrome/browser/ui/content_suggestions/identifier/content_suggestion_identifier.h" +#import "ios/chrome/browser/ui/content_suggestions/cells/suggested_content.h" // Item displaying two text labels. -@interface ContentSuggestionsTextItem - : CollectionViewItem<ContentSuggestionIdentification> +@interface ContentSuggestionsTextItem : CollectionViewItem<SuggestedContent> @property(nonatomic, nullable, copy) NSString* text; @property(nonatomic, nullable, copy) NSString* detailText;
diff --git a/ios/chrome/browser/ui/content_suggestions/cells/content_suggestions_text_item.mm b/ios/chrome/browser/ui/content_suggestions/cells/content_suggestions_text_item.mm index 5cdf8c2..c27d2ca 100644 --- a/ios/chrome/browser/ui/content_suggestions/cells/content_suggestions_text_item.mm +++ b/ios/chrome/browser/ui/content_suggestions/cells/content_suggestions_text_item.mm
@@ -5,6 +5,7 @@ #import "ios/chrome/browser/ui/content_suggestions/cells/content_suggestions_text_item.h" #import "ios/chrome/browser/ui/collection_view/cells/collection_view_text_cell.h" +#import "ios/chrome/browser/ui/content_suggestions/identifier/content_suggestion_identifier.h" #import "ios/third_party/material_components_ios/src/components/Palettes/src/MaterialPalettes.h" #import "ios/third_party/material_components_ios/src/components/Typography/src/MaterialTypography.h" @@ -17,6 +18,9 @@ @synthesize text = _text; @synthesize detailText = _detailText; @synthesize suggestionIdentifier = _suggestionIdentifier; +@synthesize attributes = _attributes; +@synthesize delegate = _delegate; +@synthesize image = _image; - (instancetype)initWithType:(NSInteger)type { self = [super initWithType:type];
diff --git a/ios/chrome/browser/ui/content_suggestions/cells/suggested_content.h b/ios/chrome/browser/ui/content_suggestions/cells/suggested_content.h new file mode 100644 index 0000000..0145854 --- /dev/null +++ b/ios/chrome/browser/ui/content_suggestions/cells/suggested_content.h
@@ -0,0 +1,37 @@ +// Copyright 2017 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. + +#ifndef IOS_CHROME_BROWSER_UI_CONTENT_SUGGESTIONS_CELLS_SUGGESTED_CONTENT_H_ +#define IOS_CHROME_BROWSER_UI_CONTENT_SUGGESTIONS_CELLS_SUGGESTED_CONTENT_H_ + +#import <UIKit/UIKit.h> + +@class CollectionViewItem; +@class ContentSuggestionIdentifier; +@class FaviconAttributes; +@protocol SuggestedContent; + +// Delegate for SuggestedContent. +@protocol SuggestedContentDelegate + +// Loads the image associated with the |suggestedItem|. +- (void)loadImageForSuggestedItem: + (CollectionViewItem<SuggestedContent>*)suggestedItem; + +@end + +// Behavior shared by the items in ContentSuggestions. +@protocol SuggestedContent + +@property(nonatomic, weak) id<SuggestedContentDelegate> delegate; +// Image associated with this content. +@property(nonatomic, strong) UIImage* image; +// Attributes for favicon. +@property(nonatomic, strong) FaviconAttributes* attributes; +// Identifier for this content. +@property(nonatomic, strong) ContentSuggestionIdentifier* suggestionIdentifier; + +@end + +#endif // IOS_CHROME_BROWSER_UI_CONTENT_SUGGESTIONS_CELLS_SUGGESTED_CONTENT_H_
diff --git a/ios/chrome/browser/ui/content_suggestions/content_suggestion.h b/ios/chrome/browser/ui/content_suggestions/content_suggestion.h deleted file mode 100644 index 0e4e7b5e..0000000 --- a/ios/chrome/browser/ui/content_suggestions/content_suggestion.h +++ /dev/null
@@ -1,50 +0,0 @@ -// Copyright 2017 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. - -#ifndef IOS_CHROME_BROWSER_UI_CONTENT_SUGGESTIONS_CONTENT_SUGGESTION_H_ -#define IOS_CHROME_BROWSER_UI_CONTENT_SUGGESTIONS_CONTENT_SUGGESTION_H_ - -#import <UIKit/UIKit.h> - -#import "ios/chrome/browser/ui/content_suggestions/identifier/content_suggestion_identifier.h" - -namespace base { -class Time; -} - -class GURL; - -// Enum defining the type of a ContentSuggestions. -typedef NS_ENUM(NSInteger, ContentSuggestionType) { - // Use this type to pass information about an empty section. Suggestion of - // this type are empty and should not be displayed. The informations to be - // displayed are contained in the SectionInfo. - ContentSuggestionTypeEmpty, - ContentSuggestionTypeArticle, - ContentSuggestionTypeReadingList, - ContentSuggestionTypeMostVisited, -}; - -// Data for a suggestions item, compatible with Objective-C. Mostly acts as a -// wrapper for ntp_snippets::ContentSuggestion. -@interface ContentSuggestion : NSObject<ContentSuggestionIdentification> - -// Title of the suggestion. -@property(nonatomic, copy, nullable) NSString* title; -// Text for the suggestion. -@property(nonatomic, copy, nullable) NSString* text; -// URL associated with the suggestion. -@property(nonatomic, assign) GURL url; -// The name of the publisher. -@property(nonatomic, copy, nullable) NSString* publisher; -// The date of publication. -@property(nonatomic, assign) base::Time publishDate; -// Whether the suggestion is available offline. -@property(nonatomic, assign) BOOL availableOffline; - -@property(nonatomic, assign) ContentSuggestionType type; - -@end - -#endif // IOS_CHROME_BROWSER_UI_CONTENT_SUGGESTIONS_CONTENT_SUGGESTION_H_
diff --git a/ios/chrome/browser/ui/content_suggestions/content_suggestion.mm b/ios/chrome/browser/ui/content_suggestions/content_suggestion.mm deleted file mode 100644 index 4b1e873..0000000 --- a/ios/chrome/browser/ui/content_suggestions/content_suggestion.mm +++ /dev/null
@@ -1,25 +0,0 @@ -// Copyright 2017 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. - -#import "ios/chrome/browser/ui/content_suggestions/content_suggestion.h" - -#include "base/time/time.h" -#include "url/gurl.h" - -#if !defined(__has_feature) || !__has_feature(objc_arc) -#error "This file requires ARC support." -#endif - -@implementation ContentSuggestion - -@synthesize title = _title; -@synthesize text = _text; -@synthesize url = _url; -@synthesize publisher = _publisher; -@synthesize publishDate = _publishDate; -@synthesize suggestionIdentifier = _suggestionIdentifier; -@synthesize availableOffline = _availableOffline; -@synthesize type = _type; - -@end
diff --git a/ios/chrome/browser/ui/content_suggestions/content_suggestions_collection_updater.h b/ios/chrome/browser/ui/content_suggestions/content_suggestions_collection_updater.h index 1dd77ec..97b1567 100644 --- a/ios/chrome/browser/ui/content_suggestions/content_suggestions_collection_updater.h +++ b/ios/chrome/browser/ui/content_suggestions/content_suggestions_collection_updater.h
@@ -7,11 +7,22 @@ #import <UIKit/UIKit.h> -#import "ios/chrome/browser/ui/content_suggestions/content_suggestion.h" - @class CollectionViewItem; -@protocol ContentSuggestionsDataSource; +@class ContentSuggestionsSectionInformation; @class ContentSuggestionsViewController; +@protocol ContentSuggestionsDataSource; +@protocol SuggestedContent; + +// Enum defining the type of a ContentSuggestions. +typedef NS_ENUM(NSInteger, ContentSuggestionType) { + // Use this type to pass information about an empty section. Suggestion of + // this type are empty and should not be displayed. The informations to be + // displayed are contained in the SectionInfo. + ContentSuggestionTypeEmpty, + ContentSuggestionTypeArticle, + ContentSuggestionTypeReadingList, + ContentSuggestionTypeMostVisited, +}; // Updater for a CollectionViewController populating it with some items and // handling the items addition. @@ -25,7 +36,7 @@ // |collectionViewController| this Updater will update. Needs to be set before // adding items. -@property(nonatomic, assign) +@property(nonatomic, weak) ContentSuggestionsViewController* collectionViewController; // Returns whether the section should use the default, non-card style. @@ -36,16 +47,18 @@ // Adds the sections for the |suggestions| to the model and returns their // indices. -- (NSIndexSet*)addSectionsForSuggestionsToModel: - (NSArray<ContentSuggestion*>*)suggestions; +- (NSIndexSet*)addSectionsForSectionInfoToModel: + (NSArray<ContentSuggestionsSectionInformation*>*)sectionsInfo; -// Adds the |suggestions| to the model and returns their index paths. -// The caller must ensure the corresponding sections have been added to the -// model. -- (NSArray<NSIndexPath*>*)addSuggestionsToModel: - (NSArray<ContentSuggestion*>*)suggestions; +// Adds the |suggestions| to the model in the section corresponding to +// |sectionInfo| and returns their index paths. The caller must ensure the +// corresponding section has been added to the model. +- (NSArray<NSIndexPath*>*) +addSuggestionsToModel: + (NSArray<CollectionViewItem<SuggestedContent>*>*)suggestions + withSectionInfo:(ContentSuggestionsSectionInformation*)sectionInfo; -// Adds the empty item to this |section| and returns its index path. The updater +// Adds an empty item to this |section| and returns its index path. The updater // does not do any check about the number of elements in the section. - (NSIndexPath*)addEmptyItemForSection:(NSInteger)section;
diff --git a/ios/chrome/browser/ui/content_suggestions/content_suggestions_collection_updater.mm b/ios/chrome/browser/ui/content_suggestions/content_suggestions_collection_updater.mm index 089fa5d8..997ff50 100644 --- a/ios/chrome/browser/ui/content_suggestions/content_suggestions_collection_updater.mm +++ b/ios/chrome/browser/ui/content_suggestions/content_suggestions_collection_updater.mm
@@ -9,6 +9,7 @@ #include "base/strings/sys_string_conversions.h" #include "base/time/time.h" #include "components/strings/grit/components_strings.h" +#import "ios/chrome/browser/ui/collection_view/cells/collection_view_item+collection_view_controller.h" #import "ios/chrome/browser/ui/collection_view/cells/collection_view_text_item.h" #import "ios/chrome/browser/ui/collection_view/collection_view_controller.h" #import "ios/chrome/browser/ui/collection_view/collection_view_model.h" @@ -16,7 +17,7 @@ #import "ios/chrome/browser/ui/content_suggestions/cells/content_suggestions_item.h" #import "ios/chrome/browser/ui/content_suggestions/cells/content_suggestions_most_visited_item.h" #import "ios/chrome/browser/ui/content_suggestions/cells/content_suggestions_text_item.h" -#import "ios/chrome/browser/ui/content_suggestions/content_suggestion.h" +#import "ios/chrome/browser/ui/content_suggestions/cells/suggested_content.h" #import "ios/chrome/browser/ui/content_suggestions/content_suggestions_data_sink.h" #import "ios/chrome/browser/ui/content_suggestions/content_suggestions_data_source.h" #import "ios/chrome/browser/ui/content_suggestions/content_suggestions_image_fetcher.h" @@ -33,8 +34,7 @@ namespace { -using CSCollectionViewItem = - CollectionViewItem<ContentSuggestionIdentification>; +using CSCollectionViewItem = CollectionViewItem<SuggestedContent>; using CSCollectionViewModel = CollectionViewModel<CSCollectionViewItem*>; // Enum defining the ItemType of this ContentSuggestionsCollectionUpdater. @@ -45,8 +45,11 @@ ItemTypeEmpty, ItemTypeReadingList, ItemTypeMostVisited, + ItemTypeUnknown, }; +// Enum defining the SectionIdentifier of this +// ContentSuggestionsCollectionUpdater. typedef NS_ENUM(NSInteger, SectionIdentifier) { SectionIdentifierArticles = kSectionIdentifierEnumZero, SectionIdentifierReadingList, @@ -54,20 +57,7 @@ SectionIdentifierDefault, }; -// Update ContentSuggestionTypeForItemType if you update this function. -ItemType ItemTypeForContentSuggestionType(ContentSuggestionType type) { - switch (type) { - case ContentSuggestionTypeArticle: - return ItemTypeArticle; - case ContentSuggestionTypeEmpty: - return ItemTypeEmpty; - case ContentSuggestionTypeReadingList: - return ItemTypeReadingList; - case ContentSuggestionTypeMostVisited: - return ItemTypeMostVisited; - } -} - +// Returns the ContentSuggestionType associated with an ItemType |type|. ContentSuggestionType ContentSuggestionTypeForItemType(NSInteger type) { if (type == ItemTypeArticle) return ContentSuggestionTypeArticle; @@ -84,15 +74,28 @@ } // Returns the section identifier corresponding to the section |info|. +ItemType ItemTypeForInfo(ContentSuggestionsSectionInformation* info) { + switch (info.sectionID) { + case ContentSuggestionsSectionArticles: + return ItemTypeArticle; + case ContentSuggestionsSectionReadingList: + return ItemTypeReadingList; + case ContentSuggestionsSectionMostVisited: + return ItemTypeMostVisited; + + case ContentSuggestionsSectionUnknown: + return ItemTypeUnknown; + } +} + +// Returns the section identifier corresponding to the section |info|. SectionIdentifier SectionIdentifierForInfo( ContentSuggestionsSectionInformation* info) { switch (info.sectionID) { case ContentSuggestionsSectionArticles: return SectionIdentifierArticles; - case ContentSuggestionsSectionReadingList: return SectionIdentifierReadingList; - case ContentSuggestionsSectionMostVisited: return SectionIdentifierMostVisited; @@ -103,9 +106,8 @@ } // namespace -@interface ContentSuggestionsCollectionUpdater ()< - ContentSuggestionsItemDelegate, - ContentSuggestionsDataSink> +@interface ContentSuggestionsCollectionUpdater ()<ContentSuggestionsDataSink, + SuggestedContentDelegate> @property(nonatomic, weak) id<ContentSuggestionsDataSource> dataSource; @property(nonatomic, strong) @@ -157,7 +159,8 @@ } [self.collectionViewController - addSuggestions:[self.dataSource suggestionsForSection:sectionInfo]]; + addSuggestions:[self.dataSource itemsForSectionInfo:sectionInfo] + toSectionInfo:sectionInfo]; } - (void)clearSuggestion:(ContentSuggestionIdentifier*)suggestionIdentifier { @@ -193,9 +196,14 @@ // The data is reset, add the new data directly in the model then reload the // collection. - NSArray<ContentSuggestion*>* suggestions = [self.dataSource allSuggestions]; - [self addSectionsForSuggestionsToModel:suggestions]; - [self addSuggestionsToModel:suggestions]; + NSArray<ContentSuggestionsSectionInformation*>* sectionInfos = + [self.dataSource sectionsInfo]; + [self addSectionsForSectionInfoToModel:sectionInfos]; + for (ContentSuggestionsSectionInformation* sectionInfo in sectionInfos) { + [self + addSuggestionsToModel:[self.dataSource itemsForSectionInfo:sectionInfo] + withSectionInfo:sectionInfo]; + } [self.collectionViewController.collectionView reloadData]; } @@ -230,135 +238,97 @@ return ContentSuggestionTypeForItemType(item.type); } -- (NSArray<NSIndexPath*>*)addSuggestionsToModel: - (NSArray<ContentSuggestion*>*)suggestions { - if (suggestions.count == 0) { - return [NSArray array]; - } +- (NSArray<NSIndexPath*>*) +addSuggestionsToModel:(NSArray<CSCollectionViewItem*>*)suggestions + withSectionInfo:(ContentSuggestionsSectionInformation*)sectionInfo { + NSMutableArray<NSIndexPath*>* indexPaths = [NSMutableArray array]; CSCollectionViewModel* model = self.collectionViewController.collectionViewModel; - NSMutableArray<NSIndexPath*>* indexPaths = [NSMutableArray array]; - for (ContentSuggestion* suggestion in suggestions) { - ContentSuggestionsSectionInformation* sectionInfo = - suggestion.suggestionIdentifier.sectionInfo; - NSInteger sectionIdentifier = SectionIdentifierForInfo(sectionInfo); + NSInteger sectionIdentifier = SectionIdentifierForInfo(sectionInfo); - if (![model hasSectionForSectionIdentifier:sectionIdentifier]) - continue; - - NSInteger section = [model sectionForSectionIdentifier:sectionIdentifier]; - NSIndexPath* indexPath = [NSIndexPath indexPathForItem:0 inSection:section]; - - if (suggestion.type != ContentSuggestionTypeEmpty && - [model hasItemAtIndexPath:indexPath] && - [model itemAtIndexPath:indexPath].type == ItemTypeEmpty) { - [self.collectionViewController dismissEntryAtIndexPath:indexPath]; + if (suggestions.count == 0) { + if ([model hasSectionForSectionIdentifier:sectionIdentifier] && + [model numberOfItemsInSection:[model sectionForSectionIdentifier: + sectionIdentifier]] == 0) { + [indexPaths + addObject:[self + addEmptyItemForSection:[model + sectionForSectionIdentifier: + sectionIdentifier]]]; } - - switch (suggestion.type) { - case ContentSuggestionTypeEmpty: { - if ([model hasSectionForSectionIdentifier:sectionIdentifier] && - [model numberOfItemsInSection:[model sectionForSectionIdentifier: - sectionIdentifier]] == 0) { - CSCollectionViewItem* item = - [self emptyItemForSectionInfo:sectionInfo]; - NSIndexPath* addedIndexPath = - [self addItem:item toSectionWithIdentifier:sectionIdentifier]; - [indexPaths addObject:addedIndexPath]; - } - break; - } - case ContentSuggestionTypeArticle: { - ContentSuggestionsItem* articleItem = - [self suggestionItemForSuggestion:suggestion]; - - articleItem.hasImage = YES; - - __weak ContentSuggestionsItem* weakItem = articleItem; - [self fetchFaviconForItem:articleItem - withURL:articleItem.URL - callback:^void(FaviconAttributes* attributes) { - weakItem.attributes = attributes; - }]; - - __weak ContentSuggestionsCollectionUpdater* weakSelf = self; - [self.dataSource - fetchFaviconImageForSuggestion:articleItem.suggestionIdentifier - completion:^void(UIImage* favicon) { - ContentSuggestionsCollectionUpdater* - strongSelf = weakSelf; - ContentSuggestionsItem* strongItem = weakItem; - if (!strongItem || !strongSelf) - return; - - strongItem.attributes = [FaviconAttributes - attributesWithImage:favicon]; - [strongSelf.collectionViewController - reconfigureCellsForItems:@[ strongItem ]]; - }]; - - NSIndexPath* addedIndexPath = [self addItem:articleItem - toSectionWithIdentifier:sectionIdentifier]; - [indexPaths addObject:addedIndexPath]; - break; - } - case ContentSuggestionTypeReadingList: { - ContentSuggestionsItem* readingListItem = - [self suggestionItemForSuggestion:suggestion]; - - __weak ContentSuggestionsItem* weakItem = readingListItem; - [self fetchFaviconForItem:readingListItem - withURL:readingListItem.URL - callback:^void(FaviconAttributes* attributes) { - weakItem.attributes = attributes; - }]; - - NSIndexPath* addedIndexPath = [self addItem:readingListItem - toSectionWithIdentifier:sectionIdentifier]; - [indexPaths addObject:addedIndexPath]; - break; - } - case ContentSuggestionTypeMostVisited: { - ContentSuggestionsMostVisitedItem* mostVisitedItem = - [[ContentSuggestionsMostVisitedItem alloc] - initWithType:ItemTypeMostVisited]; - mostVisitedItem.title = suggestion.title; - [model addItem:mostVisitedItem - toSectionWithIdentifier:SectionIdentifierMostVisited]; - [indexPaths addObject:indexPath]; - break; - } - } + return indexPaths; } + BOOL emptyItemRemoved = NO; + NSArray<CSCollectionViewItem*>* existingItems = + [model itemsInSectionWithIdentifier:sectionIdentifier]; + if (existingItems.count > 0 && existingItems[0].type == ItemTypeEmpty) { + [model removeItemWithType:ItemTypeEmpty + fromSectionWithIdentifier:sectionIdentifier]; + emptyItemRemoved = YES; + } + + [suggestions enumerateObjectsUsingBlock:^(CSCollectionViewItem* item, + NSUInteger index, BOOL* stop) { + ItemType type = ItemTypeForInfo(sectionInfo); + item.type = type; + NSIndexPath* addedIndexPath = + [self addItem:item toSectionWithIdentifier:sectionIdentifier]; + [self fetchFaviconForItem:item]; + item.delegate = self; + + if (!emptyItemRemoved || index > 0) { + [indexPaths addObject:addedIndexPath]; + } else { + [self.collectionViewController.collectionViewLayout invalidateLayout]; + } + }]; + return indexPaths; } -- (NSIndexSet*)addSectionsForSuggestionsToModel: - (NSArray<ContentSuggestion*>*)suggestions { - NSMutableIndexSet* indexSet = [NSMutableIndexSet indexSet]; +- (NSIndexSet*)addSectionsForSectionInfoToModel: + (NSArray<ContentSuggestionsSectionInformation*>*)sectionsInfo { + NSMutableIndexSet* addedSectionIdentifiers = [NSMutableIndexSet indexSet]; + NSArray<ContentSuggestionsSectionInformation*>* orderedSectionsInfo = + [self.dataSource sectionsInfo]; CSCollectionViewModel* model = self.collectionViewController.collectionViewModel; - for (ContentSuggestion* suggestion in suggestions) { - ContentSuggestionsSectionInformation* sectionInfo = - suggestion.suggestionIdentifier.sectionInfo; + for (ContentSuggestionsSectionInformation* sectionInfo in sectionsInfo) { NSInteger sectionIdentifier = SectionIdentifierForInfo(sectionInfo); if ([model hasSectionForSectionIdentifier:sectionIdentifier] || - (suggestion.type == ContentSuggestionTypeEmpty && - !sectionInfo.showIfEmpty)) { + (!sectionInfo.showIfEmpty && + [self.dataSource itemsForSectionInfo:sectionInfo].count == 0)) { continue; } - [model addSectionWithIdentifier:sectionIdentifier]; - self.sectionInfoBySectionIdentifier[@(sectionIdentifier)] = sectionInfo; - [indexSet addIndex:[model sectionForSectionIdentifier:sectionIdentifier]]; + NSUInteger sectionIndex = 0; + for (ContentSuggestionsSectionInformation* orderedSectionInfo in + orderedSectionsInfo) { + NSInteger orderedSectionIdentifier = + SectionIdentifierForInfo(orderedSectionInfo); + if ([model hasSectionForSectionIdentifier:orderedSectionIdentifier]) { + sectionIndex++; + } + } + [model insertSectionWithIdentifier:sectionIdentifier atIndex:sectionIndex]; - [self addHeader:sectionInfo]; + self.sectionInfoBySectionIdentifier[@(sectionIdentifier)] = sectionInfo; + [addedSectionIdentifiers addIndex:sectionIdentifier]; + + [self addHeaderIfNeeded:sectionInfo]; [self addFooterIfNeeded:sectionInfo]; } + + NSMutableIndexSet* indexSet = [NSMutableIndexSet indexSet]; + [addedSectionIdentifiers enumerateIndexesUsingBlock:^( + NSUInteger sectionIdentifier, + BOOL* _Nonnull stop) { + [indexSet addIndex:[model sectionForSectionIdentifier:sectionIdentifier]]; + }]; return indexSet; } @@ -373,26 +343,26 @@ return [self addItem:item toSectionWithIdentifier:sectionIdentifier]; } -#pragma mark - ContentSuggestionsItemDelegate +#pragma mark - SuggestedContentDelegate -- (void)loadImageForSuggestionItem:(ContentSuggestionsItem*)suggestionItem { +- (void)loadImageForSuggestedItem:(CSCollectionViewItem*)suggestedItem { __weak ContentSuggestionsCollectionUpdater* weakSelf = self; - __weak ContentSuggestionsItem* weakArticle = suggestionItem; + __weak CSCollectionViewItem* weakItem = suggestedItem; void (^imageFetchedCallback)(UIImage*) = ^(UIImage* image) { ContentSuggestionsCollectionUpdater* strongSelf = weakSelf; - ContentSuggestionsItem* strongArticle = weakArticle; - if (!strongSelf || !strongArticle) { + CSCollectionViewItem* strongItem = weakItem; + if (!strongSelf || !strongItem) { return; } - strongArticle.image = image; + strongItem.image = image; [strongSelf.collectionViewController - reconfigureCellsForItems:@[ strongArticle ]]; + reconfigureCellsForItems:@[ strongItem ]]; }; [self.dataSource.imageFetcher - fetchImageForSuggestion:suggestionItem.suggestionIdentifier + fetchImageForSuggestion:suggestedItem.suggestionIdentifier callback:imageFetchedCallback]; } @@ -420,12 +390,14 @@ } } -// Adds the header corresponding to |sectionInfo| to the section. -- (void)addHeader:(ContentSuggestionsSectionInformation*)sectionInfo { +// Adds the header corresponding to |sectionInfo| to the section if there is +// none present and the section info contains a title. +- (void)addHeaderIfNeeded:(ContentSuggestionsSectionInformation*)sectionInfo { NSInteger sectionIdentifier = SectionIdentifierForInfo(sectionInfo); if (![self.collectionViewController.collectionViewModel - headerForSectionWithIdentifier:sectionIdentifier]) { + headerForSectionWithIdentifier:sectionIdentifier] && + sectionInfo.title) { CollectionViewTextItem* header = [[CollectionViewTextItem alloc] initWithType:ItemTypeHeader]; header.text = sectionInfo.title; @@ -442,11 +414,58 @@ self.sectionInfoBySectionIdentifier = [[NSMutableDictionary alloc] init]; } +// Fetches the favicon attributes for the |item|. +- (void)fetchFaviconForItem:(CSCollectionViewItem*)item { + __weak ContentSuggestionsCollectionUpdater* weakSelf = self; + __weak CSCollectionViewItem* weakItem = item; + + [self.dataSource + fetchFaviconAttributesForItem:item + completion:^(FaviconAttributes* attributes) { + ContentSuggestionsCollectionUpdater* strongSelf = + weakSelf; + CSCollectionViewItem* strongItem = weakItem; + if (!strongSelf || !strongItem) { + return; + } + + strongItem.attributes = attributes; + [strongSelf.collectionViewController + reconfigureCellsForItems:@[ strongItem ]]; + + [strongSelf fetchFaviconImageForItem:strongItem]; + }]; +} + +// Fetches the favicon image for the |item|. +- (void)fetchFaviconImageForItem:(CSCollectionViewItem*)item { + __weak ContentSuggestionsCollectionUpdater* weakSelf = self; + __weak CSCollectionViewItem* weakItem = item; + + [self.dataSource + fetchFaviconImageForItem:item + completion:^(UIImage* image) { + ContentSuggestionsCollectionUpdater* strongSelf = + weakSelf; + CSCollectionViewItem* strongItem = weakItem; + if (!strongSelf || !strongItem || !image) { + return; + } + + strongItem.attributes = + [FaviconAttributes attributesWithImage:image]; + [strongSelf.collectionViewController + reconfigureCellsForItems:@[ strongItem ]]; + }]; +} + // Runs the additional action for the section identified by |sectionInfo|. - (void)runAdditionalActionForSection: (ContentSuggestionsSectionInformation*)sectionInfo { SectionIdentifier sectionIdentifier = SectionIdentifierForInfo(sectionInfo); + // TODO(crbug.com/721229): Start spinner. + NSMutableArray<ContentSuggestionIdentifier*>* knownSuggestionIdentifiers = [NSMutableArray array]; @@ -463,15 +482,23 @@ [self.dataSource fetchMoreSuggestionsKnowing:knownSuggestionIdentifiers fromSectionInfo:sectionInfo - callback:^(NSArray<ContentSuggestion*>* suggestions) { - [weakSelf moreSuggestionsFetched:suggestions]; + callback:^( + NSArray<CSCollectionViewItem*>* suggestions) { + [weakSelf moreSuggestionsFetched:suggestions + inSectionInfo:sectionInfo]; }]; } // Adds the |suggestions| to the collection view. All the suggestions must have // the same sectionInfo. -- (void)moreSuggestionsFetched:(NSArray<ContentSuggestion*>*)suggestions { - [self.collectionViewController addSuggestions:suggestions]; +- (void)moreSuggestionsFetched:(NSArray<CSCollectionViewItem*>*)suggestions + inSectionInfo: + (ContentSuggestionsSectionInformation*)sectionInfo { + if (suggestions) { + [self.collectionViewController addSuggestions:suggestions + toSectionInfo:sectionInfo]; + } + // TODO(crbug.com/721229):Stop spinner. } // Returns a item to be displayed when the section identified by |sectionInfo| @@ -486,52 +513,6 @@ return item; } -// Returns a suggestion item built with the |suggestion|. -- (ContentSuggestionsItem*)suggestionItemForSuggestion: - (ContentSuggestion*)suggestion { - ContentSuggestionsItem* suggestionItem = [[ContentSuggestionsItem alloc] - initWithType:ItemTypeForContentSuggestionType(suggestion.type) - title:suggestion.title - subtitle:suggestion.text - delegate:self - url:suggestion.url]; - - suggestionItem.publisher = suggestion.publisher; - suggestionItem.publishDate = suggestion.publishDate; - suggestionItem.availableOffline = suggestion.availableOffline; - - suggestionItem.suggestionIdentifier = suggestion.suggestionIdentifier; - - return suggestionItem; -} - -// Fetches the favicon associated with the |URL|, call the |callback| with the -// attributes then reconfigure the |item|. -- (void)fetchFaviconForItem:(CSCollectionViewItem*)item - withURL:(const GURL&)URL - callback:(void (^)(FaviconAttributes*))callback { - if (!callback) - return; - - __weak ContentSuggestionsCollectionUpdater* weakSelf = self; - __weak CSCollectionViewItem* weakItem = item; - void (^completionBlock)(FaviconAttributes* attributes) = - ^(FaviconAttributes* attributes) { - CSCollectionViewItem* strongItem = weakItem; - ContentSuggestionsCollectionUpdater* strongSelf = weakSelf; - if (!strongSelf || !strongItem) { - return; - } - - callback(attributes); - - [strongSelf.collectionViewController - reconfigureCellsForItems:@[ strongItem ]]; - }; - - [self.dataSource fetchFaviconAttributesForURL:URL completion:completionBlock]; -} - // Adds |item| to |sectionIdentifier| section of the model of the // CollectionView. Returns the IndexPath of the newly added item. - (NSIndexPath*)addItem:(CSCollectionViewItem*)item
diff --git a/ios/chrome/browser/ui/content_suggestions/content_suggestions_collection_updater_unittest.mm b/ios/chrome/browser/ui/content_suggestions/content_suggestions_collection_updater_unittest.mm index 71956f2..edfdf4f 100644 --- a/ios/chrome/browser/ui/content_suggestions/content_suggestions_collection_updater_unittest.mm +++ b/ios/chrome/browser/ui/content_suggestions/content_suggestions_collection_updater_unittest.mm
@@ -5,7 +5,8 @@ #import "ios/chrome/browser/ui/content_suggestions/content_suggestions_collection_updater.h" #import "ios/chrome/browser/ui/collection_view/collection_view_model.h" -#import "ios/chrome/browser/ui/content_suggestions/content_suggestion.h" +#import "ios/chrome/browser/ui/content_suggestions/cells/content_suggestions_text_item.h" +#import "ios/chrome/browser/ui/content_suggestions/cells/suggested_content.h" #import "ios/chrome/browser/ui/content_suggestions/content_suggestions_view_controller.h" #import "ios/chrome/browser/ui/content_suggestions/identifier/content_suggestion_identifier.h" #import "ios/chrome/browser/ui/content_suggestions/identifier/content_suggestions_section_information.h" @@ -28,13 +29,16 @@ OCMStub([mockCollection collectionViewModel]).andReturn(model); updater.collectionViewController = mockCollection; - ContentSuggestion* suggestion = [[ContentSuggestion alloc] init]; + CollectionViewItem<SuggestedContent>* suggestion = + [[ContentSuggestionsTextItem alloc] initWithType:kItemTypeEnumZero]; suggestion.suggestionIdentifier = [[ContentSuggestionIdentifier alloc] init]; suggestion.suggestionIdentifier.sectionInfo = [[ContentSuggestionsSectionInformation alloc] initWithSectionID:ContentSuggestionsSectionArticles]; suggestion.suggestionIdentifier.sectionInfo.showIfEmpty = YES; - [updater addSectionsForSuggestionsToModel:@[ suggestion ]]; + [updater addSectionsForSectionInfoToModel:@[ + suggestion.suggestionIdentifier.sectionInfo + ]]; ASSERT_EQ(0, [model numberOfItemsInSection:0]); // Action. @@ -54,14 +58,18 @@ OCMStub([mockCollection collectionViewModel]).andReturn(model); updater.collectionViewController = mockCollection; - ContentSuggestion* suggestion = [[ContentSuggestion alloc] init]; + CollectionViewItem<SuggestedContent>* suggestion = + [[ContentSuggestionsTextItem alloc] initWithType:kItemTypeEnumZero]; suggestion.suggestionIdentifier = [[ContentSuggestionIdentifier alloc] init]; suggestion.suggestionIdentifier.sectionInfo = [[ContentSuggestionsSectionInformation alloc] initWithSectionID:ContentSuggestionsSectionArticles]; suggestion.suggestionIdentifier.sectionInfo.showIfEmpty = YES; - [updater addSectionsForSuggestionsToModel:@[ suggestion ]]; - [updater addSuggestionsToModel:@[ suggestion ]]; + [updater addSectionsForSectionInfoToModel:@[ + suggestion.suggestionIdentifier.sectionInfo + ]]; + [updater addSuggestionsToModel:@[ suggestion ] + withSectionInfo:suggestion.suggestionIdentifier.sectionInfo]; ASSERT_EQ(1, [model numberOfItemsInSection:0]); // Action.
diff --git a/ios/chrome/browser/ui/content_suggestions/content_suggestions_data_source.h b/ios/chrome/browser/ui/content_suggestions/content_suggestions_data_source.h index 671b7f1..5ea35b4 100644 --- a/ios/chrome/browser/ui/content_suggestions/content_suggestions_data_source.h +++ b/ios/chrome/browser/ui/content_suggestions/content_suggestions_data_source.h
@@ -5,16 +5,20 @@ #ifndef IOS_CHROME_BROWSER_UI_CONTENT_SUGGESTIONS_CONTENT_SUGGESTIONS_DATA_SOURCE_H_ #define IOS_CHROME_BROWSER_UI_CONTENT_SUGGESTIONS_CONTENT_SUGGESTIONS_DATA_SOURCE_H_ +#import <UIKit/UIKit.h> + +@class CollectionViewItem; @class ContentSuggestion; @class ContentSuggestionIdentifier; @class ContentSuggestionsSectionInformation; @class FaviconAttributes; @protocol ContentSuggestionsDataSink; @protocol ContentSuggestionsImageFetcher; -class GURL; +@protocol SuggestedContent; // Typedef for a block taking the fetched suggestions as parameter. -typedef void (^MoreSuggestionsFetched)(NSArray<ContentSuggestion*>* _Nonnull); +typedef void (^MoreSuggestionsFetched)( + NSArray<CollectionViewItem<SuggestedContent>*>* _Nullable); // DataSource for the content suggestions. Provides the suggestions data in a // format compatible with Objective-C. @@ -23,30 +27,30 @@ // The data sink that will be notified when the data change. @property(nonatomic, nullable, weak) id<ContentSuggestionsDataSink> dataSink; -// Returns all the data currently available. -- (nonnull NSArray<ContentSuggestion*>*)allSuggestions; +// Returns all the sections information in the order they should be displayed. +- (nonnull NSArray<ContentSuggestionsSectionInformation*>*)sectionsInfo; -// Returns the data currently available for the section identified by -// |sectionInfo|. -- (nonnull NSArray<ContentSuggestion*>*)suggestionsForSection: +// Returns the items associated with the |sectionInfo|. +- (nonnull NSArray<CollectionViewItem<SuggestedContent>*>*)itemsForSectionInfo: (nonnull ContentSuggestionsSectionInformation*)sectionInfo; // Returns an image updater for the suggestions provided by this data source. - (nullable id<ContentSuggestionsImageFetcher>)imageFetcher; -// Fetches favicon attributes and calls the completion block. -- (void)fetchFaviconAttributesForURL:(const GURL&)URL - completion: - (void (^_Nonnull)(FaviconAttributes* _Nonnull)) - completion; +// Fetches favicon attributes associated with the |item| and calls the +// |completion| block. +- (void)fetchFaviconAttributesForItem: + (nonnull CollectionViewItem<SuggestedContent>*)item + completion: + (void (^_Nonnull)(FaviconAttributes* _Nonnull)) + completion; -// Fetches favicon image associated with this |suggestion| in history. If it is -// not present in the history, tries to download it. Calls the completion block -// if an image has been found. -// This can only be used for public URL. +// Fetches the favicon image associated with the |item|. If there is no image +// cached locally and the provider allows it, it tries to download it. The +// |completion| block is only called if an image is found. - (void) -fetchFaviconImageForSuggestion:(nonnull ContentSuggestionIdentifier*)suggestion - completion:(void (^_Nonnull)(UIImage* _Nonnull))completion; +fetchFaviconImageForItem:(nonnull CollectionViewItem<SuggestedContent>*)item + completion:(void (^_Nonnull)(UIImage* _Nonnull))completion; // Fetches additional content. All the |knownSuggestions| must come from the // same |sectionInfo|. If the fetch was completed, the given |callback| is @@ -56,7 +60,7 @@ fromSectionInfo: (nonnull ContentSuggestionsSectionInformation*) sectionInfo - callback:(nullable MoreSuggestionsFetched)callback; + callback:(nonnull MoreSuggestionsFetched)callback; @end
diff --git a/ios/chrome/browser/ui/content_suggestions/content_suggestions_view_controller.h b/ios/chrome/browser/ui/content_suggestions/content_suggestions_view_controller.h index b529127..88d7457 100644 --- a/ios/chrome/browser/ui/content_suggestions/content_suggestions_view_controller.h +++ b/ios/chrome/browser/ui/content_suggestions/content_suggestions_view_controller.h
@@ -9,10 +9,10 @@ #import "ios/chrome/browser/ui/collection_view/collection_view_controller.h" -@class ContentSuggestion; +@class ContentSuggestionsSectionInformation; @protocol ContentSuggestionsCommands; @protocol ContentSuggestionsDataSource; -@protocol ContentSuggestionIdentification; +@protocol SuggestedContent; // CollectionViewController to display the suggestions items. @interface ContentSuggestionsViewController : CollectionViewController @@ -29,15 +29,18 @@ suggestionCommandHandler; // Override from superclass to have a more specific type. @property(nonatomic, readonly) - CollectionViewModel<CollectionViewItem<ContentSuggestionIdentification>*>* + CollectionViewModel<CollectionViewItem<SuggestedContent>*>* collectionViewModel; // Removes the entry at |indexPath|, from the collection and its model. - (void)dismissEntryAtIndexPath:(NSIndexPath*)indexPath; // Removes the |section|. - (void)dismissSection:(NSInteger)section; -// Adds the |suggestions| to the collection and its model. -- (void)addSuggestions:(NSArray<ContentSuggestion*>*)suggestions; +// Adds the |suggestions| to the collection and its model in the section +// corresponding to |sectionInfo|. +- (void)addSuggestions: + (NSArray<CollectionViewItem<SuggestedContent>*>*)suggestions + toSectionInfo:(ContentSuggestionsSectionInformation*)sectionInfo; @end
diff --git a/ios/chrome/browser/ui/content_suggestions/content_suggestions_view_controller.mm b/ios/chrome/browser/ui/content_suggestions/content_suggestions_view_controller.mm index ba83a32a..5e7741ec 100644 --- a/ios/chrome/browser/ui/content_suggestions/content_suggestions_view_controller.mm +++ b/ios/chrome/browser/ui/content_suggestions/content_suggestions_view_controller.mm
@@ -9,7 +9,6 @@ #import "ios/chrome/browser/ui/collection_view/cells/collection_view_item.h" #import "ios/chrome/browser/ui/collection_view/collection_view_model.h" #import "ios/chrome/browser/ui/content_suggestions/cells/content_suggestions_item.h" -#import "ios/chrome/browser/ui/content_suggestions/content_suggestion.h" #import "ios/chrome/browser/ui/content_suggestions/content_suggestions_collection_updater.h" #import "ios/chrome/browser/ui/content_suggestions/content_suggestions_commands.h" #include "url/gurl.h" @@ -18,6 +17,10 @@ #error "This file requires ARC support." #endif +namespace { +using CSCollectionViewItem = CollectionViewItem<SuggestedContent>; +} + @interface ContentSuggestionsViewController () @property(nonatomic, strong) @@ -81,21 +84,23 @@ }]; } -- (void)addSuggestions:(NSArray<ContentSuggestion*>*)suggestions { +- (void)addSuggestions:(NSArray<CSCollectionViewItem*>*)suggestions + toSectionInfo:(ContentSuggestionsSectionInformation*)sectionInfo { if (suggestions.count == 0) { return; } [self.collectionView performBatchUpdates:^{ - NSIndexSet* addedSections = - [self.collectionUpdater addSectionsForSuggestionsToModel:suggestions]; + NSIndexSet* addedSections = [self.collectionUpdater + addSectionsForSectionInfoToModel:@[ sectionInfo ]]; [self.collectionView insertSections:addedSections]; } completion:nil]; [self.collectionView performBatchUpdates:^{ NSArray<NSIndexPath*>* addedItems = - [self.collectionUpdater addSuggestionsToModel:suggestions]; + [self.collectionUpdater addSuggestionsToModel:suggestions + withSectionInfo:sectionInfo]; [self.collectionView insertItemsAtIndexPaths:addedItems]; } completion:nil];
diff --git a/ios/chrome/browser/ui/content_suggestions/identifier/content_suggestion_identifier.h b/ios/chrome/browser/ui/content_suggestions/identifier/content_suggestion_identifier.h index a85ff6e5..5586e5e1 100644 --- a/ios/chrome/browser/ui/content_suggestions/identifier/content_suggestion_identifier.h +++ b/ios/chrome/browser/ui/content_suggestions/identifier/content_suggestion_identifier.h
@@ -20,11 +20,4 @@ @end -// A protocol for an object having an ID. -@protocol ContentSuggestionIdentification - -@property(nonatomic, strong) ContentSuggestionIdentifier* suggestionIdentifier; - -@end - #endif // IOS_CHROME_BROWSER_UI_CONTENT_SUGGESTIONS_IDENTIFIER_CONTENT_SUGGESTION_IDENTIFIER_H_
diff --git a/ios/chrome/browser/ui/content_suggestions/identifier/content_suggestions_section_information.h b/ios/chrome/browser/ui/content_suggestions/identifier/content_suggestions_section_information.h index f2f2d8b4..e2aea5a 100644 --- a/ios/chrome/browser/ui/content_suggestions/identifier/content_suggestions_section_information.h +++ b/ios/chrome/browser/ui/content_suggestions/identifier/content_suggestions_section_information.h
@@ -15,10 +15,8 @@ ContentSuggestionsSectionLayoutCustom, }; -// This enum is used for ordering the sections and as ID for the section. Make -// all sections in the same collection have different ID. -// When adding a new kind of suggestions, add a new corresponding section. The -// ordering is not persisted between launch, reordering is possible. +// This enum is used for identifying the section. All section should have a +// different ID. typedef NS_ENUM(NSInteger, ContentSuggestionsSectionID) { ContentSuggestionsSectionMostVisited = 0, ContentSuggestionsSectionArticles,
diff --git a/ios/chrome/browser/ui/elements/activity_overlay_coordinator.mm b/ios/chrome/browser/ui/elements/activity_overlay_coordinator.mm index 8ff7dc09..f56daeec 100644 --- a/ios/chrome/browser/ui/elements/activity_overlay_coordinator.mm +++ b/ios/chrome/browser/ui/elements/activity_overlay_coordinator.mm
@@ -4,11 +4,13 @@ #import "ios/chrome/browser/ui/elements/activity_overlay_coordinator.h" -#include "base/mac/objc_release_properties.h" +#import "base/mac/objc_property_releaser.h" #import "ios/chrome/browser/ui/elements/activity_overlay_view_controller.h" #import "ios/chrome/browser/ui/uikit_ui_util.h" -@interface ActivityOverlayCoordinator () +@interface ActivityOverlayCoordinator () { + base::mac::ObjCPropertyReleaser _propertyReleaser_ActivityOverlayCoordinator; +} // View controller that displays an activity indicator. @property(nonatomic, retain) UIViewController* activityOverlayViewController; @@ -18,9 +20,14 @@ @synthesize activityOverlayViewController = _activityOverlayViewController; -- (void)dealloc { - base::mac::ReleaseProperties(self); - [super dealloc]; +- (nullable instancetype)initWithBaseViewController: + (UIViewController*)viewController { + self = [super initWithBaseViewController:viewController]; + if (self) { + _propertyReleaser_ActivityOverlayCoordinator.Init( + self, [ActivityOverlayCoordinator class]); + } + return self; } - (void)start {
diff --git a/ios/chrome/browser/ui/main/browser_view_wrangler.mm b/ios/chrome/browser/ui/main/browser_view_wrangler.mm index 1ea694b..ef7f08f 100644 --- a/ios/chrome/browser/ui/main/browser_view_wrangler.mm +++ b/ios/chrome/browser/ui/main/browser_view_wrangler.mm
@@ -4,7 +4,7 @@ #import "ios/chrome/browser/ui/main/browser_view_wrangler.h" -#include "base/mac/objc_release_properties.h" +#include "base/mac/objc_property_releaser.h" #import "base/mac/scoped_nsobject.h" #include "base/strings/sys_string_conversions.h" #include "ios/chrome/browser/application_context.h" @@ -27,6 +27,8 @@ @interface BrowserViewWrangler ()<TabModelObserver> { ios::ChromeBrowserState* _browserState; __unsafe_unretained id<TabModelObserver> _tabModelObserver; + + base::mac::ObjCPropertyReleaser _propertyReleaser_BrowserViewWrangler; } // Responsible for maintaining all state related to sharing to other devices. @@ -66,6 +68,8 @@ - (instancetype)initWithBrowserState:(ios::ChromeBrowserState*)browserState tabModelObserver:(id<TabModelObserver>)tabModelObserver { if ((self = [super init])) { + _propertyReleaser_BrowserViewWrangler.Init(self, + [BrowserViewWrangler class]); _browserState = browserState; _tabModelObserver = tabModelObserver; } @@ -97,7 +101,6 @@ [_mainTabModel browserStateDestroyed]; [_otrTabModel browserStateDestroyed]; - base::mac::ReleaseProperties(self); [super dealloc]; }
diff --git a/ios/chrome/browser/ui/ntp/new_tab_page_bar.mm b/ios/chrome/browser/ui/ntp/new_tab_page_bar.mm index 5cedf9c..760902a 100644 --- a/ios/chrome/browser/ui/ntp/new_tab_page_bar.mm +++ b/ios/chrome/browser/ui/ntp/new_tab_page_bar.mm
@@ -8,7 +8,7 @@ #include <cmath> #include "base/logging.h" -#include "base/mac/objc_release_properties.h" +#include "base/mac/objc_property_releaser.h" #include "base/mac/scoped_nsobject.h" #import "ios/chrome/browser/ui/bookmarks/bookmark_utils_ios.h" #import "ios/chrome/browser/ui/ntp/new_tab_page_bar_button.h" @@ -66,6 +66,8 @@ CGFloat buttonWidth_; // Percentage overlay sits over tab bar buttons. CGFloat overlayPercentage_; + + base::mac::ObjCPropertyReleaser propertyReleaser_NewTabPageBar_; } @synthesize items = items_; @@ -92,6 +94,7 @@ } - (void)setup { + propertyReleaser_NewTabPageBar_.Init(self, [NewTabPageBar class]); self.selectedIndex = NSNotFound; canAnimate_ = NO; self.autoresizingMask = @@ -130,11 +133,6 @@ self.contentMode = UIViewContentModeRedraw; } -- (void)dealloc { - base::mac::ReleaseProperties(self); - [super dealloc]; -} - - (void)layoutSubviews { [super layoutSubviews];
diff --git a/ios/chrome/browser/ui/ntp/new_tab_page_bar_button.mm b/ios/chrome/browser/ui/ntp/new_tab_page_bar_button.mm index 658f4256..91580eee 100644 --- a/ios/chrome/browser/ui/ntp/new_tab_page_bar_button.mm +++ b/ios/chrome/browser/ui/ntp/new_tab_page_bar_button.mm
@@ -5,7 +5,7 @@ #import "ios/chrome/browser/ui/ntp/new_tab_page_bar_button.h" #include "base/logging.h" -#include "base/mac/objc_release_properties.h" +#include "base/mac/objc_property_releaser.h" #import "ios/chrome/browser/ui/ntp/new_tab_page_bar_item.h" #import "ios/chrome/browser/ui/uikit_ui_util.h" #import "ios/third_party/material_components_ios/src/components/Typography/src/MaterialTypography.h" @@ -27,6 +27,7 @@ UIImage* _image; NSString* _title; + base::mac::ObjCPropertyReleaser _propertyReleaser_NewTabPageBarButton; } @property(nonatomic, retain) UIColor* color; @@ -61,6 +62,8 @@ DCHECK(item.image); NewTabPageBarButton* button = [[self class] buttonWithType:UIButtonTypeCustom]; + button->_propertyReleaser_NewTabPageBarButton.Init( + button, [NewTabPageBarButton class]); button.title = item.title; button.image = @@ -82,11 +85,6 @@ return button; } -- (void)dealloc { - base::mac::ReleaseProperties(self); - [super dealloc]; -} - - (void)useIncognitoColorScheme:(CGFloat)percentage { DCHECK(percentage >= 0 && percentage <= 1); self.interpolatedColor =
diff --git a/ios/chrome/browser/ui/ntp/new_tab_page_bar_item.mm b/ios/chrome/browser/ui/ntp/new_tab_page_bar_item.mm index 90075680..915497f3 100644 --- a/ios/chrome/browser/ui/ntp/new_tab_page_bar_item.mm +++ b/ios/chrome/browser/ui/ntp/new_tab_page_bar_item.mm
@@ -4,7 +4,7 @@ #import "ios/chrome/browser/ui/ntp/new_tab_page_bar_item.h" -#include "base/mac/objc_release_properties.h" +#include "base/mac/objc_property_releaser.h" @implementation NewTabPageBarItem { // Title of the button. @@ -15,6 +15,7 @@ UIImage* image_; // New tab page view. __unsafe_unretained UIView* view_; // weak + base::mac::ObjCPropertyReleaser propertyReleaser_NewTabPageBarItem_; } @synthesize title = title_; @@ -34,9 +35,12 @@ return item; } -- (void)dealloc { - base::mac::ReleaseProperties(self); - [super dealloc]; +- (id)init { + self = [super init]; + if (self) { + propertyReleaser_NewTabPageBarItem_.Init(self, [NewTabPageBarItem class]); + } + return self; } @end
diff --git a/ios/chrome/browser/ui/ntp/new_tab_page_controller.mm b/ios/chrome/browser/ui/ntp/new_tab_page_controller.mm index 43818934..60b9af7 100644 --- a/ios/chrome/browser/ui/ntp/new_tab_page_controller.mm +++ b/ios/chrome/browser/ui/ntp/new_tab_page_controller.mm
@@ -8,7 +8,7 @@ #import "base/ios/weak_nsobject.h" #include "base/logging.h" -#include "base/mac/objc_release_properties.h" +#include "base/mac/objc_property_releaser.h" #include "base/metrics/user_metrics.h" #include "base/metrics/user_metrics_action.h" #include "components/prefs/pref_service.h" @@ -131,6 +131,8 @@ base::WeakNSProtocol<id<WebToolbarDelegate>> webToolbarDelegate_; base::scoped_nsobject<TabModel> tabModel_; + + base::mac::ObjCPropertyReleaser propertyReleaser_NewTabPageController_; } // Load and bring panel into view. @@ -196,6 +198,8 @@ self = [super initWithNibName:nil url:url]; if (self) { DCHECK(browserState); + propertyReleaser_NewTabPageController_.Init(self, + [NewTabPageController class]); browserState_ = browserState; loader_ = loader; newTabPageObserver_ = ntpObserver; @@ -313,7 +317,6 @@ [bookmarkController_ setDelegate:nil]; [openTabsController_ setDelegate:nil]; [[NSNotificationCenter defaultCenter] removeObserver:self]; - base::mac::ReleaseProperties(self); [super dealloc]; }
diff --git a/ios/chrome/browser/ui/ntp/new_tab_page_view.mm b/ios/chrome/browser/ui/ntp/new_tab_page_view.mm index 95996a5..5245ee5 100644 --- a/ios/chrome/browser/ui/ntp/new_tab_page_view.mm +++ b/ios/chrome/browser/ui/ntp/new_tab_page_view.mm
@@ -5,7 +5,7 @@ #import "ios/chrome/browser/ui/ntp/new_tab_page_view.h" #include "base/logging.h" -#include "base/mac/objc_release_properties.h" +#include "base/mac/objc_property_releaser.h" #import "ios/chrome/browser/ui/ntp/new_tab_page_bar.h" #import "ios/chrome/browser/ui/ntp/new_tab_page_bar_item.h" #import "ios/chrome/browser/ui/rtl_geometry.h" @@ -17,6 +17,8 @@ // subviews already. __unsafe_unretained NewTabPageBar* tabBar_; // weak __unsafe_unretained UIScrollView* scrollView_; // weak + + base::mac::ObjCPropertyReleaser propertyReleaser_NewTabPageView_; } @synthesize scrollView = scrollView_; @@ -27,6 +29,7 @@ andTabBar:(NewTabPageBar*)tabBar { self = [super initWithFrame:frame]; if (self) { + propertyReleaser_NewTabPageView_.Init(self, [NewTabPageView class]); [self addSubview:scrollView]; [self addSubview:tabBar]; scrollView_ = scrollView; @@ -45,11 +48,6 @@ return nil; } -- (void)dealloc { - base::mac::ReleaseProperties(self); - [super dealloc]; -} - - (void)setFrame:(CGRect)frame { // When transitioning the iPhone xib to an iPad idiom, the setFrame call below // can sometimes fire a scrollViewDidScroll event which changes the
diff --git a/ios/chrome/browser/ui/overscroll_actions/overscroll_actions_controller.mm b/ios/chrome/browser/ui/overscroll_actions/overscroll_actions_controller.mm index 5d26414f..b1049d4 100644 --- a/ios/chrome/browser/ui/overscroll_actions/overscroll_actions_controller.mm +++ b/ios/chrome/browser/ui/overscroll_actions/overscroll_actions_controller.mm
@@ -8,7 +8,7 @@ #include <algorithm> #include "base/logging.h" -#include "base/mac/objc_release_properties.h" +#include "base/mac/objc_property_releaser.h" #include "base/mac/scoped_nsobject.h" #include "base/metrics/histogram_macros.h" #import "ios/chrome/browser/ui/browser_view_controller.h" @@ -168,6 +168,7 @@ // The scrollview driving the OverscrollActionsController when not using // the scrollview from the CRWWebControllerObserver. base::scoped_nsobject<UIScrollView> _scrollview; + base::mac::ObjCPropertyReleaser _propertyReleaser_OverscrollActionsController; } // The view displayed over the header view holding the actions. @@ -245,6 +246,8 @@ - (instancetype)initWithScrollView:(UIScrollView*)scrollView { self = [super init]; if (self) { + _propertyReleaser_OverscrollActionsController.Init( + self, [OverscrollActionsController class]); _overscrollActionView = [[OverscrollActionsView alloc] initWithFrame:CGRectZero]; _overscrollActionView.delegate = self; @@ -277,7 +280,6 @@ - (void)dealloc { self.overscrollActionView.delegate = nil; [self invalidate]; - base::mac::ReleaseProperties(self); [super dealloc]; }
diff --git a/ios/chrome/browser/ui/overscroll_actions/overscroll_actions_view.mm b/ios/chrome/browser/ui/overscroll_actions/overscroll_actions_view.mm index 4333cdb..9e2768c 100644 --- a/ios/chrome/browser/ui/overscroll_actions/overscroll_actions_view.mm +++ b/ios/chrome/browser/ui/overscroll_actions/overscroll_actions_view.mm
@@ -7,7 +7,7 @@ #import <QuartzCore/QuartzCore.h> #include "base/logging.h" -#include "base/mac/objc_release_properties.h" +#include "base/mac/objc_property_releaser.h" #include "base/mac/scoped_nsobject.h" #include "ios/chrome/browser/ui/rtl_geometry.h" #include "ios/chrome/browser/ui/uikit_ui_util.h" @@ -134,6 +134,7 @@ // The array is built the first time the method -layersToCenterVertically is // called. base::scoped_nsobject<NSArray> _layersToCenterVertically; + base::mac::ObjCPropertyReleaser _propertyReleaser_OverscrollActionsView; } // Redefined to readwrite. @@ -241,6 +242,8 @@ - (instancetype)initWithFrame:(CGRect)frame { self = [super initWithFrame:frame]; if (self) { + _propertyReleaser_OverscrollActionsView.Init(self, + [OverscrollActionsView class]); _deformationBehaviorEnabled = YES; self.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight; @@ -302,7 +305,6 @@ - (void)dealloc { [self.snapshotView removeFromSuperview]; - base::mac::ReleaseProperties(self); [super dealloc]; }
diff --git a/ios/chrome/browser/ui/popup_menu/popup_menu_controller.mm b/ios/chrome/browser/ui/popup_menu/popup_menu_controller.mm index 5d528dfa..6784433 100644 --- a/ios/chrome/browser/ui/popup_menu/popup_menu_controller.mm +++ b/ios/chrome/browser/ui/popup_menu/popup_menu_controller.mm
@@ -7,7 +7,7 @@ #import "base/ios/weak_nsobject.h" #include "base/logging.h" #include "base/mac/bundle_locations.h" -#include "base/mac/objc_release_properties.h" +#include "base/mac/objc_property_releaser.h" #import "ios/chrome/browser/ui/animation_util.h" #import "ios/chrome/browser/ui/popup_menu/popup_menu_view.h" #include "ios/chrome/browser/ui/rtl_geometry.h" @@ -55,6 +55,7 @@ } // anonymous namespace @interface PopupMenuController ()<PopupMenuViewDelegate> { + base::mac::ObjCPropertyReleaser propertyReleaser_PopupMenuController_; CGPoint sourceAnimationPoint_; } @end @@ -84,6 +85,9 @@ DCHECK(parent); self = [super init]; if (self) { + propertyReleaser_PopupMenuController_.Init(self, + [PopupMenuController class]); + popupContainer_ = [[PopupMenuView alloc] initWithFrame:CGRectMake(0, 0, kPopupContainerWidth, kPopupContainerHeight)]; @@ -172,7 +176,6 @@ [popupContainer_ removeFromSuperview]; [backgroundButton_ removeFromSuperview]; [containerView_ removeFromSuperview]; - base::mac::ReleaseProperties(self); [super dealloc]; }
diff --git a/ios/chrome/browser/ui/settings/material_cell_catalog_view_controller.mm b/ios/chrome/browser/ui/settings/material_cell_catalog_view_controller.mm index 924dde3..12b9a80 100644 --- a/ios/chrome/browser/ui/settings/material_cell_catalog_view_controller.mm +++ b/ios/chrome/browser/ui/settings/material_cell_catalog_view_controller.mm
@@ -731,7 +731,6 @@ subtitle:@"Really, this is the best article I have ever seen, it " @"is mandatory to read it! It describes how to write " @"the best article." - delegate:nil url:GURL()]; articleItem.publisher = @"Top Publisher.com"; return articleItem;
diff --git a/ios/chrome/browser/ui/settings/save_passwords_collection_view_controller.mm b/ios/chrome/browser/ui/settings/save_passwords_collection_view_controller.mm index 5475996..742b1c7 100644 --- a/ios/chrome/browser/ui/settings/save_passwords_collection_view_controller.mm +++ b/ios/chrome/browser/ui/settings/save_passwords_collection_view_controller.mm
@@ -11,7 +11,7 @@ #import "base/ios/weak_nsobject.h" #include "base/logging.h" #include "base/mac/foundation_util.h" -#import "base/mac/objc_release_properties.h" +#import "base/mac/objc_property_releaser.h" #import "base/mac/scoped_nsobject.h" #include "base/memory/ptr_util.h" #include "base/numerics/safe_conversions.h" @@ -162,6 +162,9 @@ // Module containing the reauthentication mechanism for viewing and copying // passwords. base::scoped_nsobject<ReauthenticationModule> reauthenticationModule_; + + base::mac::ObjCPropertyReleaser + propertyReleaser_SavePasswordsCollectionViewController_; } // Kick off async request to get logins from password store. - (void)getLoginsFromPasswordStore; @@ -191,13 +194,15 @@ [self getLoginsFromPasswordStore]; [self updateEditButton]; [self loadModel]; + + propertyReleaser_SavePasswordsCollectionViewController_.Init( + self, [SavePasswordsCollectionViewController class]); } return self; } - (void)dealloc { [passwordManagerEnabled_ setObserver:nil]; - base::mac::ReleaseProperties(self); [super dealloc]; }
diff --git a/ios/chrome/browser/ui/settings/settings_root_collection_view_controller.mm b/ios/chrome/browser/ui/settings/settings_root_collection_view_controller.mm index adbdd0a..d259ef5 100644 --- a/ios/chrome/browser/ui/settings/settings_root_collection_view_controller.mm +++ b/ios/chrome/browser/ui/settings/settings_root_collection_view_controller.mm
@@ -7,7 +7,7 @@ #include "base/ios/ios_util.h" #include "base/logging.h" #import "base/mac/foundation_util.h" -#import "base/mac/objc_release_properties.h" +#import "base/mac/objc_property_releaser.h" #import "base/mac/scoped_nsobject.h" #include "ios/chrome/browser/browser_state/chrome_browser_state.h" #import "ios/chrome/browser/ui/commands/UIKit+ChromeExecuteCommand.h" @@ -39,15 +39,22 @@ SavedBarButtomItemPositionEnum savedBarButtonItemPosition_; base::scoped_nsobject<UIBarButtonItem> savedBarButtonItem_; base::scoped_nsobject<UIView> veil_; + + base::mac::ObjCPropertyReleaser + propertyReleaser_SettingsRootCollectionViewController_; } @synthesize shouldHideDoneButton = shouldHideDoneButton_; @synthesize collectionViewAccessibilityIdentifier = collectionViewAccessibilityIdentifier_; -- (void)dealloc { - base::mac::ReleaseProperties(self); - [super dealloc]; +- (instancetype)initWithStyle:(CollectionViewControllerStyle)style { + self = [super initWithStyle:style]; + if (self) { + propertyReleaser_SettingsRootCollectionViewController_.Init( + self, [SettingsRootCollectionViewController class]); + } + return self; } - (void)viewDidLoad {
diff --git a/ios/chrome/browser/ui/settings/sync_encryption_passphrase_collection_view_controller.mm b/ios/chrome/browser/ui/settings/sync_encryption_passphrase_collection_view_controller.mm index 9744b78..2ccd5b3 100644 --- a/ios/chrome/browser/ui/settings/sync_encryption_passphrase_collection_view_controller.mm +++ b/ios/chrome/browser/ui/settings/sync_encryption_passphrase_collection_view_controller.mm
@@ -8,7 +8,7 @@ #include "base/i18n/time_formatting.h" #include "base/mac/foundation_util.h" -#import "base/mac/objc_release_properties.h" +#import "base/mac/objc_property_releaser.h" #import "base/mac/scoped_nsobject.h" #include "base/strings/sys_string_conversions.h" #include "components/browser_sync/profile_sync_service.h" @@ -65,6 +65,8 @@ std::unique_ptr<SyncObserverBridge> syncObserver_; std::unique_ptr<OAuth2TokenServiceObserverBridge> tokenServiceObserver_; base::scoped_nsobject<UITextField> passphrase_; + base::mac::ObjCPropertyReleaser + propertyReleaser_SyncEncryptionPassphraseCollectionViewController_; } // Sets up the navigation bar's right button. The button will be enabled iff @@ -140,16 +142,14 @@ tokenServiceObserver_.reset(new OAuth2TokenServiceObserverBridge( OAuth2TokenServiceFactory::GetForBrowserState(browserState_), self)); + propertyReleaser_SyncEncryptionPassphraseCollectionViewController_.Init( + self, [SyncEncryptionPassphraseCollectionViewController class]); + [self loadModel]; } return self; } -- (void)dealloc { - base::mac::ReleaseProperties(self); - [super dealloc]; -} - - (UITextField*)passphrase { return passphrase_; }
diff --git a/ios/chrome/browser/ui/stack_view/card_view.mm b/ios/chrome/browser/ui/stack_view/card_view.mm index 62a810a..0ca24d4 100644 --- a/ios/chrome/browser/ui/stack_view/card_view.mm +++ b/ios/chrome/browser/ui/stack_view/card_view.mm
@@ -26,7 +26,7 @@ #include <algorithm> #import "base/mac/foundation_util.h" -#include "base/mac/objc_release_properties.h" +#import "base/mac/objc_property_releaser.h" #import "base/mac/scoped_nsobject.h" #include "components/strings/grit/components_strings.h" #import "ios/chrome/browser/ui/animation_util.h" @@ -124,7 +124,9 @@ @end -@implementation CardTabView +@implementation CardTabView { + base::mac::ObjCPropertyReleaser _propertyReleaser_CardTabView; +} #pragma mark - Property Implementation @@ -144,6 +146,7 @@ if (!self) return self; + _propertyReleaser_CardTabView.Init(self, [CardTabView class]); _isIncognito = isIncognito; UIImage* image = ImageWithName(@"default_favicon", _isIncognito); @@ -175,11 +178,6 @@ return nil; } -- (void)dealloc { - base::mac::ReleaseProperties(self); - [super dealloc]; -} - - (void)setCloseButtonSide:(CardCloseButtonSide)closeButtonSide { if (_closeButtonSide != closeButtonSide) { _closeButtonSide = closeButtonSide;
diff --git a/ios/chrome/browser/ui/stack_view/stack_view_controller.mm b/ios/chrome/browser/ui/stack_view/stack_view_controller.mm index d17b5d6..cdb4ba2b 100644 --- a/ios/chrome/browser/ui/stack_view/stack_view_controller.mm +++ b/ios/chrome/browser/ui/stack_view/stack_view_controller.mm
@@ -16,7 +16,7 @@ #include "base/logging.h" #import "base/mac/bundle_locations.h" #import "base/mac/foundation_util.h" -#include "base/mac/objc_release_properties.h" +#import "base/mac/objc_property_releaser.h" #include "base/mac/scoped_block.h" #import "base/mac/scoped_nsobject.h" #include "base/metrics/histogram_macros.h" @@ -489,6 +489,8 @@ // |YES| if there is card set animation being processed. For testing only. // Save last touch point used by new tab animation. CGPoint _lastTapPoint; + + base::mac::ObjCPropertyReleaser _propertyReleaserStackViewController; } @synthesize activeCardSet = _activeCardSet; @@ -511,6 +513,8 @@ DCHECK(activeCardSet == otrCardSet || activeCardSet == mainCardSet); self = [super initWithNibName:nil bundle:nil]; if (self) { + _propertyReleaserStackViewController.Init(self, + [StackViewController class]); [self setUpWithMainCardSet:mainCardSet otrCardSet:otrCardSet activeCardSet:activeCardSet]; @@ -812,7 +816,6 @@ [_mainCardSet setObserver:nil]; [_otrCardSet setObserver:nil]; [self cleanUpViewsAndNotifications]; - base::mac::ReleaseProperties(self); [super dealloc]; }
diff --git a/ios/chrome/browser/ui/tabs/tab_strip_controller.mm b/ios/chrome/browser/ui/tabs/tab_strip_controller.mm index 7f3f0c4..c09b68a3 100644 --- a/ios/chrome/browser/ui/tabs/tab_strip_controller.mm +++ b/ios/chrome/browser/ui/tabs/tab_strip_controller.mm
@@ -12,7 +12,7 @@ #import "base/ios/weak_nsobject.h" #include "base/mac/bundle_locations.h" #include "base/mac/foundation_util.h" -#include "base/mac/objc_release_properties.h" +#include "base/mac/objc_property_releaser.h" #include "base/mac/scoped_nsobject.h" #include "base/metrics/user_metrics.h" #include "base/metrics/user_metrics_action.h" @@ -183,6 +183,8 @@ // The model index of the placeholder gap, if one exists. This value is used // as the new model index of the dragged tab when it is dropped. NSUInteger _placeholderGapModelIndex; + + base::mac::ObjCPropertyReleaser _propertyReleaser_TabStripController; } @property(nonatomic, readonly, retain) TabStripView* tabStripView; @@ -324,6 +326,7 @@ - (instancetype)initWithTabModel:(TabModel*)tabModel style:(TabStrip::Style)style { if ((self = [super init])) { + _propertyReleaser_TabStripController.Init(self, [TabStripController class]); _tabArray.reset([[NSMutableArray alloc] initWithCapacity:10]); _closingTabs.reset([[NSMutableSet alloc] initWithCapacity:5]); @@ -429,7 +432,6 @@ [_tabStripView setDelegate:nil]; [_tabStripView setLayoutDelegate:nil]; [_tabModel removeObserver:self]; - base::mac::ReleaseProperties(self); [super dealloc]; }
diff --git a/ios/chrome/browser/ui/tabs/tab_view.mm b/ios/chrome/browser/ui/tabs/tab_view.mm index 00a5502..cbc9b10 100644 --- a/ios/chrome/browser/ui/tabs/tab_view.mm +++ b/ios/chrome/browser/ui/tabs/tab_view.mm
@@ -8,7 +8,7 @@ #include "base/i18n/rtl.h" #include "base/ios/ios_util.h" #include "base/logging.h" -#include "base/mac/objc_release_properties.h" +#include "base/mac/objc_property_releaser.h" #include "base/strings/sys_string_conversions.h" #import "ios/chrome/browser/ui/colors/MDCPalette+CrAdditions.h" #import "ios/chrome/browser/ui/commands/UIKit+ChromeExecuteCommand.h" @@ -72,6 +72,8 @@ BOOL _collapsed; base::scoped_nsobject<MDCActivityIndicator> _activityIndicator; + + base::mac::ObjCPropertyReleaser _propertyReleaser_TabView; } @end @@ -113,6 +115,7 @@ - (id)initWithEmptyView:(BOOL)emptyView selected:(BOOL)selected { if ((self = [super initWithFrame:CGRectZero])) { + _propertyReleaser_TabView.Init(self, [TabView class]); [self setOpaque:NO]; [self createCommonViews]; // -setSelected only calls -updateBackgroundImage if the selected state @@ -127,11 +130,6 @@ return self; } -- (void)dealloc { - base::mac::ReleaseProperties(self); - [super dealloc]; -} - - (void)setSelected:(BOOL)selected { BOOL wasSelected = [self isSelected]; [super setSelected:selected];
diff --git a/ios/chrome/browser/ui/tools_menu/tools_menu_view_controller.mm b/ios/chrome/browser/ui/tools_menu/tools_menu_view_controller.mm index 36f9c5f..e6bd954 100644 --- a/ios/chrome/browser/ui/tools_menu/tools_menu_view_controller.mm +++ b/ios/chrome/browser/ui/tools_menu/tools_menu_view_controller.mm
@@ -9,7 +9,7 @@ #include "base/ios/ios_util.h" #import "base/ios/weak_nsobject.h" #include "base/logging.h" -#include "base/mac/objc_release_properties.h" +#include "base/mac/objc_property_releaser.h" #include "base/mac/scoped_nsobject.h" #include "base/metrics/field_trial.h" #include "components/strings/grit/components_strings.h" @@ -105,6 +105,7 @@ @interface ToolsMenuViewController ()<UICollectionViewDelegateFlowLayout, UICollectionViewDataSource, ReadingListMenuNotificationDelegate> { + base::mac::ObjCPropertyReleaser _propertyReleaser_ToolsMenuViewController; BOOL _waitForInk; // Weak pointer to ReadingListMenuNotifier, used to set the starting values // for the reading list badge. @@ -335,14 +336,11 @@ } - (void)commonInitialization { + _propertyReleaser_ToolsMenuViewController.Init( + self, [ToolsMenuViewController class]); _readingListMenuNotifier.reset(); } -- (void)dealloc { - base::mac::ReleaseProperties(self); - [super dealloc]; -} - - (void)loadView { [super loadView];
diff --git a/ios/chrome/browser/ui/tools_menu/tools_menu_view_item.mm b/ios/chrome/browser/ui/tools_menu/tools_menu_view_item.mm index 182983a..9db0a61 100644 --- a/ios/chrome/browser/ui/tools_menu/tools_menu_view_item.mm +++ b/ios/chrome/browser/ui/tools_menu/tools_menu_view_item.mm
@@ -5,7 +5,7 @@ #import "ios/chrome/browser/ui/tools_menu/tools_menu_view_item.h" #include "base/i18n/rtl.h" -#include "base/mac/objc_release_properties.h" +#include "base/mac/objc_property_releaser.h" #import "ios/third_party/material_roboto_font_loader_ios/src/src/MaterialRobotoFontLoader.h" #include "ui/base/l10n/l10n_util.h" @@ -16,7 +16,9 @@ static NSString* const kMenuItemCellID = @"MenuItemCellID"; } -@implementation ToolsMenuViewItem +@implementation ToolsMenuViewItem { + base::mac::ObjCPropertyReleaser _propertyReleaser_ToolsMenuViewItem; +} @synthesize accessibilityIdentifier = _accessibilityIdentifier; @synthesize active = _active; @@ -27,17 +29,13 @@ - (id)init { self = [super init]; if (self) { + _propertyReleaser_ToolsMenuViewItem.Init(self, [ToolsMenuViewItem class]); _active = YES; } return self; } -- (void)dealloc { - base::mac::ReleaseProperties(self); - [super dealloc]; -} - + (NSString*)cellID { return kMenuItemCellID; } @@ -60,7 +58,9 @@ @end -@implementation ToolsMenuViewCell +@implementation ToolsMenuViewCell { + base::mac::ObjCPropertyReleaser _propertyReleaser_ToolsMenuViewCell; +} @synthesize title = _title; @synthesize horizontalMargin = _horizontalMargin; @@ -82,17 +82,13 @@ } - (void)commonInitialization { + _propertyReleaser_ToolsMenuViewCell.Init(self, [ToolsMenuViewCell class]); _horizontalMargin = !base::i18n::IsRTL() ? kToolsMenuItemHorizontalMargin : kToolsMenuItemHorizontalMarginRTL; [self setBackgroundColor:[UIColor whiteColor]]; [self setOpaque:YES]; } -- (void)dealloc { - base::mac::ReleaseProperties(self); - [super dealloc]; -} - - (void)prepareForReuse { [super prepareForReuse]; [_title setText:nil];
diff --git a/ios/chrome/browser/ui/tools_menu/tools_menu_view_tools_cell.mm b/ios/chrome/browser/ui/tools_menu/tools_menu_view_tools_cell.mm index da5cc4a..e5c3b10 100644 --- a/ios/chrome/browser/ui/tools_menu/tools_menu_view_tools_cell.mm +++ b/ios/chrome/browser/ui/tools_menu/tools_menu_view_tools_cell.mm
@@ -4,7 +4,7 @@ #import "ios/chrome/browser/ui/tools_menu/tools_menu_view_tools_cell.h" -#include "base/mac/objc_release_properties.h" +#include "base/mac/objc_property_releaser.h" #include "components/strings/grit/components_strings.h" #include "ios/chrome/browser/ui/commands/ios_command_ids.h" #include "ios/chrome/browser/ui/rtl_geometry.h" @@ -18,7 +18,9 @@ // IDC_MinimumLabelValue) to avoid collisions. #define IDC_TEMP_EDIT_BOOKMARK 3900 -@implementation ToolsMenuViewToolsCell +@implementation ToolsMenuViewToolsCell { + base::mac::ObjCPropertyReleaser _propertyReleaser_ToolsMenuViewToolsCell; +} @synthesize reloadButton = _reloadButton; @synthesize shareButton = _shareButton; @@ -44,6 +46,9 @@ } - (void)commonInitialization { + _propertyReleaser_ToolsMenuViewToolsCell.Init(self, + [ToolsMenuViewToolsCell class]); + [self setBackgroundColor:[UIColor whiteColor]]; [self setOpaque:YES]; @@ -97,11 +102,6 @@ [self addConstraints]; } -- (void)dealloc { - base::mac::ReleaseProperties(self); - [super dealloc]; -} - - (UIButton*)newButtonForImageIds:(int[2][3])imageIds commandID:(int)commandID accessibilityLabelID:(int)labelID
diff --git a/ios/clean/chrome/app/steps/root_coordinator+application_step.mm b/ios/clean/chrome/app/steps/root_coordinator+application_step.mm index c6041a24..fea3ab4 100644 --- a/ios/clean/chrome/app/steps/root_coordinator+application_step.mm +++ b/ios/clean/chrome/app/steps/root_coordinator+application_step.mm
@@ -5,12 +5,14 @@ #import "ios/clean/chrome/app/steps/root_coordinator+application_step.h" #include "base/memory/ptr_util.h" -#import "base/supports_user_data.h" +#include "base/supports_user_data.h" #include "ios/chrome/browser/browser_state/chrome_browser_state.h" #import "ios/chrome/browser/web_state_list/web_state_list.h" #import "ios/clean/chrome/app/application_state.h" #import "ios/shared/chrome/browser/ui/browser_list/browser.h" #import "ios/shared/chrome/browser/ui/browser_list/browser_list.h" +#import "ios/shared/chrome/browser/ui/browser_list/browser_list_session_service.h" +#import "ios/shared/chrome/browser/ui/browser_list/browser_list_session_service_factory.h" #import "ios/shared/chrome/browser/ui/coordinators/browser_coordinator+internal.h" #import "ios/web/public/navigation_manager.h" #include "ios/web/public/web_state/web_state.h" @@ -49,16 +51,16 @@ self.browser = BrowserList::FromBrowserState(state.browserState)->CreateNewBrowser(); - // PLACEHOLDER: Create some open, empty web states. - WebStateList& webStateList = self.browser->web_state_list(); - for (int i = 0; i < 7; i++) { + BrowserListSessionService* service = + BrowserListSessionServiceFactory::GetForBrowserState(state.browserState); + + if (!service || !service->RestoreSession()) { + WebStateList& webStateList = self.browser->web_state_list(); web::WebState::CreateParams webStateCreateParams( self.browser->browser_state()); - std::unique_ptr<web::WebState> webState = - web::WebState::Create(webStateCreateParams); - webStateList.InsertWebState(0, std::move(webState)); + webStateList.InsertWebState(0, web::WebState::Create(webStateCreateParams)); + webStateList.ActivateWebStateAt(0); } - webStateList.ActivateWebStateAt(0); [self start];
diff --git a/ios/shared/chrome/browser/ui/browser_list/BUILD.gn b/ios/shared/chrome/browser/ui/browser_list/BUILD.gn index 5e01070..43231579 100644 --- a/ios/shared/chrome/browser/ui/browser_list/BUILD.gn +++ b/ios/shared/chrome/browser/ui/browser_list/BUILD.gn
@@ -10,17 +10,27 @@ "browser_list.mm", "browser_list_observer.h", "browser_list_observer.mm", + "browser_list_session_service.h", + "browser_list_session_service_factory.h", + "browser_list_session_service_factory.mm", + "browser_list_session_service_impl.h", + "browser_list_session_service_impl.mm", "browser_web_state_list_delegate.h", "browser_web_state_list_delegate.mm", ] deps = [ "//base", + "//components/keyed_service/core", + "//components/keyed_service/ios", + "//ios/chrome/browser", "//ios/chrome/browser/browser_state", "//ios/chrome/browser/find_in_page", "//ios/chrome/browser/sessions", + "//ios/chrome/browser/sessions:serialisation", "//ios/chrome/browser/ssl", "//ios/chrome/browser/web_state_list", "//ios/shared/chrome/browser/ui/commands", + "//ios/web", ] configs += [ "//build/config/compiler:enable_arc" ] }
diff --git a/ios/shared/chrome/browser/ui/browser_list/DEPS b/ios/shared/chrome/browser/ui/browser_list/DEPS new file mode 100644 index 0000000..1a098df --- /dev/null +++ b/ios/shared/chrome/browser/ui/browser_list/DEPS
@@ -0,0 +1,4 @@ +include_rules = [ + "+components/keyed_service/core", + "+components/keyed_service/ios", +]
diff --git a/ios/shared/chrome/browser/ui/browser_list/browser_list_session_service.h b/ios/shared/chrome/browser/ui/browser_list/browser_list_session_service.h new file mode 100644 index 0000000..c4803b2 --- /dev/null +++ b/ios/shared/chrome/browser/ui/browser_list/browser_list_session_service.h
@@ -0,0 +1,34 @@ +// Copyright 2017 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. + +#ifndef IOS_SHARED_CHROME_BROWSER_UI_BROWSER_LIST_BROWSER_LIST_SESSION_SERVICE_H_ +#define IOS_SHARED_CHROME_BROWSER_UI_BROWSER_LIST_BROWSER_LIST_SESSION_SERVICE_H_ + +#include "base/macros.h" +#include "components/keyed_service/core/keyed_service.h" + +// BrowserListSessionService allow saving and restoring saved sessions. +class BrowserListSessionService : public KeyedService { + public: + BrowserListSessionService() = default; + ~BrowserListSessionService() override = default; + + // Restores the saved session on the current thread. Returns whether the + // load was successful or not. + virtual bool RestoreSession() = 0; + + // Schedules deletion of the file containing the last session. + virtual void ScheduleLastSessionDeletion() = 0; + + // Schedules recording the session on a background thread. If |immediately| + // is false, then the session is recorded after a delay. In all cases, if + // another session recording was previously scheduled with a delay, that will + // be cancelled. + virtual void ScheduleSaveSession(bool immediately) = 0; + + private: + DISALLOW_COPY_AND_ASSIGN(BrowserListSessionService); +}; + +#endif // IOS_SHARED_CHROME_BROWSER_UI_BROWSER_LIST_BROWSER_LIST_SESSION_SERVICE_H_
diff --git a/ios/shared/chrome/browser/ui/browser_list/browser_list_session_service_factory.h b/ios/shared/chrome/browser/ui/browser_list/browser_list_session_service_factory.h new file mode 100644 index 0000000..f2d20de --- /dev/null +++ b/ios/shared/chrome/browser/ui/browser_list/browser_list_session_service_factory.h
@@ -0,0 +1,47 @@ +// Copyright 2017 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. + +#ifndef IOS_SHARED_CHROME_BROWSER_UI_BROWSER_LIST_BROWSER_LIST_SESSION_SERVICE_FACTORY_H_ +#define IOS_SHARED_CHROME_BROWSER_UI_BROWSER_LIST_BROWSER_LIST_SESSION_SERVICE_FACTORY_H_ + +#include "base/macros.h" +#include "components/keyed_service/ios/browser_state_keyed_service_factory.h" + +namespace base { +template <typename T> +struct DefaultSingletonTraits; +} + +namespace ios { +class ChromeBrowserState; +} + +class BrowserListSessionService; + +// BrowserListSessionServiceFactory attaches BrowserListSessionService to +// ChromeBrowserState. +class BrowserListSessionServiceFactory + : public BrowserStateKeyedServiceFactory { + public: + static BrowserListSessionService* GetForBrowserState( + ios::ChromeBrowserState* browser_state); + static BrowserListSessionServiceFactory* GetInstance(); + + private: + friend struct base::DefaultSingletonTraits<BrowserListSessionServiceFactory>; + + BrowserListSessionServiceFactory(); + ~BrowserListSessionServiceFactory() override; + + // BrowserStateKeyedServiceFactory implementation. + std::unique_ptr<KeyedService> BuildServiceInstanceFor( + web::BrowserState* context) const override; + web::BrowserState* GetBrowserStateToUse( + web::BrowserState* context) const override; + bool ServiceIsNULLWhileTesting() const override; + + DISALLOW_COPY_AND_ASSIGN(BrowserListSessionServiceFactory); +}; + +#endif // IOS_SHARED_CHROME_BROWSER_UI_BROWSER_LIST_BROWSER_LIST_SESSION_SERVICE_FACTORY_H_
diff --git a/ios/shared/chrome/browser/ui/browser_list/browser_list_session_service_factory.mm b/ios/shared/chrome/browser/ui/browser_list/browser_list_session_service_factory.mm new file mode 100644 index 0000000..f97f03b --- /dev/null +++ b/ios/shared/chrome/browser/ui/browser_list/browser_list_session_service_factory.mm
@@ -0,0 +1,89 @@ +// Copyright 2017 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. + +#import "ios/shared/chrome/browser/ui/browser_list/browser_list_session_service_factory.h" + +#include <memory> + +#include "base/bind.h" +#include "base/files/file_path.h" +#include "base/logging.h" +#include "base/memory/ptr_util.h" +#include "base/memory/singleton.h" +#include "base/strings/sys_string_conversions.h" +#include "components/keyed_service/ios/browser_state_dependency_manager.h" +#include "ios/chrome/browser/browser_state/browser_state_otr_helper.h" +#include "ios/chrome/browser/browser_state/chrome_browser_state.h" +#import "ios/chrome/browser/sessions/session_service_ios.h" +#import "ios/shared/chrome/browser/ui/browser_list/browser_list.h" +#import "ios/shared/chrome/browser/ui/browser_list/browser_list_session_service_impl.h" +#import "ios/web/public/certificate_policy_cache.h" +#import "ios/web/public/web_state/session_certificate_policy_cache.h" + +#if !defined(__has_feature) || !__has_feature(objc_arc) +#error "This file requires ARC support." +#endif + +namespace { +// WebState factory for BrowserListSessionServiceImpl. The factory is called +// to create a WebState from serialised session state, so the browser state +// certificate policy cache is updated with the information from the WebState. +std::unique_ptr<web::WebState> CreateWebState( + ios::ChromeBrowserState* browser_state, + CRWSessionStorage* session_storage) { + std::unique_ptr<web::WebState> web_state = + web::WebState::CreateWithStorageSession( + web::WebState::CreateParams(browser_state), session_storage); + web_state->GetSessionCertificatePolicyCache()->UpdateCertificatePolicyCache( + web::BrowserState::GetCertificatePolicyCache(browser_state)); + return web_state; +} +} + +// static +BrowserListSessionService* BrowserListSessionServiceFactory::GetForBrowserState( + ios::ChromeBrowserState* browser_state) { + return static_cast<BrowserListSessionService*>( + GetInstance()->GetServiceForBrowserState(browser_state, true)); +} + +// static +BrowserListSessionServiceFactory* +BrowserListSessionServiceFactory::GetInstance() { + return base::Singleton<BrowserListSessionServiceFactory>::get(); +} + +BrowserListSessionServiceFactory::BrowserListSessionServiceFactory() + : BrowserStateKeyedServiceFactory( + "BrowserListSessionService", + BrowserStateDependencyManager::GetInstance()) {} + +BrowserListSessionServiceFactory::~BrowserListSessionServiceFactory() {} + +std::unique_ptr<KeyedService> +BrowserListSessionServiceFactory::BuildServiceInstanceFor( + web::BrowserState* context) const { + ios::ChromeBrowserState* browser_state = + ios::ChromeBrowserState::FromBrowserState(context); + // It is safe to use base::Unretained here as BrowserListSessionServiceImpl + // will be destroyed before the ChromeBrowserState (as it is a KeyedService). + return base::MakeUnique<BrowserListSessionServiceImpl>( + BrowserList::FromBrowserState(browser_state), + base::SysUTF8ToNSString(browser_state->GetStatePath().AsUTF8Unsafe()), + [SessionServiceIOS sharedService], + base::BindRepeating(&CreateWebState, base::Unretained(browser_state))); +} + +web::BrowserState* BrowserListSessionServiceFactory::GetBrowserStateToUse( + web::BrowserState* context) const { + // The off-the-record ChromeBrowserState has its own BrowserListSessionService + // to implement restoring the sessions after the application has been evicted + // while in the background. + return GetBrowserStateOwnInstanceInIncognito(context); +} + +bool BrowserListSessionServiceFactory::ServiceIsNULLWhileTesting() const { + // Avoid automatically saving session during unit tests. + return true; +}
diff --git a/ios/shared/chrome/browser/ui/browser_list/browser_list_session_service_impl.h b/ios/shared/chrome/browser/ui/browser_list/browser_list_session_service_impl.h new file mode 100644 index 0000000..ed69309 --- /dev/null +++ b/ios/shared/chrome/browser/ui/browser_list/browser_list_session_service_impl.h
@@ -0,0 +1,60 @@ +// Copyright 2017 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. + +#ifndef IOS_SHARED_CHROME_BROWSER_UI_BROWSER_LIST_BROWSER_LIST_SESSION_SERVICE_IMPL_H_ +#define IOS_SHARED_CHROME_BROWSER_UI_BROWSER_LIST_BROWSER_LIST_SESSION_SERVICE_IMPL_H_ + +#import <Foundation/Foundation.h> + +#include <memory> + +#include "base/callback.h" +#include "base/macros.h" +#import "ios/shared/chrome/browser/ui/browser_list/browser_list_session_service.h" +#import "ios/web/public/web_state/web_state.h" + +class BrowserList; +class BrowserListObserver; +@class CRWSessionStorage; +@class SessionServiceIOS; + +namespace web { +class WebState; +} + +// Implementation of BrowserListSessionService that automatically track the +// active WebStates of |browser_list| and save the session when the active +// WebState changes or a new navigation item is committed. +class BrowserListSessionServiceImpl : public BrowserListSessionService { + public: + // Callback used to create WebStates when restoring a session. + using CreateWebStateCallback = + base::RepeatingCallback<std::unique_ptr<web::WebState>( + CRWSessionStorage*)>; + + BrowserListSessionServiceImpl(BrowserList* browser_list, + NSString* session_directory, + SessionServiceIOS* session_service, + const CreateWebStateCallback& create_web_state); + ~BrowserListSessionServiceImpl() override; + + // BrowserListSessionService implementation. + bool RestoreSession() override; + void ScheduleLastSessionDeletion() override; + void ScheduleSaveSession(bool immediately) override; + + // KeyedService implementation. + void Shutdown() override; + + private: + BrowserList* browser_list_; + __strong NSString* session_directory_; + __strong SessionServiceIOS* session_service_; + CreateWebStateCallback create_web_state_; + std::unique_ptr<BrowserListObserver> observer_; + + DISALLOW_COPY_AND_ASSIGN(BrowserListSessionServiceImpl); +}; + +#endif // IOS_SHARED_CHROME_BROWSER_UI_BROWSER_LIST_BROWSER_LIST_SESSION_SERVICE_IMPL_H_
diff --git a/ios/shared/chrome/browser/ui/browser_list/browser_list_session_service_impl.mm b/ios/shared/chrome/browser/ui/browser_list/browser_list_session_service_impl.mm new file mode 100644 index 0000000..4604cdf --- /dev/null +++ b/ios/shared/chrome/browser/ui/browser_list/browser_list_session_service_impl.mm
@@ -0,0 +1,291 @@ +// Copyright 2017 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. + +#import "ios/shared/chrome/browser/ui/browser_list/browser_list_session_service_impl.h" + +#include <map> + +#include "base/bind.h" +#include "base/callback.h" +#include "base/logging.h" +#include "base/memory/ptr_util.h" +#include "ios/chrome/browser/chrome_url_constants.h" +#import "ios/chrome/browser/sessions/session_ios.h" +#import "ios/chrome/browser/sessions/session_service_ios.h" +#import "ios/chrome/browser/sessions/session_window_ios.h" +#import "ios/chrome/browser/web_state_list/web_state_list.h" +#import "ios/chrome/browser/web_state_list/web_state_list_observer.h" +#import "ios/chrome/browser/web_state_list/web_state_list_serialization.h" +#import "ios/shared/chrome/browser/ui/browser_list/browser.h" +#import "ios/shared/chrome/browser/ui/browser_list/browser_list.h" +#import "ios/shared/chrome/browser/ui/browser_list/browser_list_observer.h" +#import "ios/web/public/navigation_item.h" +#import "ios/web/public/navigation_manager.h" +#import "ios/web/public/web_state/web_state.h" +#import "ios/web/public/web_state/web_state_observer.h" + +#if !defined(__has_feature) || !__has_feature(objc_arc) +#error "This file requires ARC support." +#endif + +namespace { + +// BrowserListSessionServiceWebStateObserver observes a WebState and invokes +// |closure| when a new navigation item is committed. +class BrowserListSessionServiceWebStateObserver : public web::WebStateObserver { + public: + explicit BrowserListSessionServiceWebStateObserver( + const base::RepeatingClosure& closure); + ~BrowserListSessionServiceWebStateObserver() override; + + // Changes the observed WebState to |web_state|. + void ObserveWebState(web::WebState* web_state); + + // web::WebStateObserver implementation. + void NavigationItemCommitted( + const web::LoadCommittedDetails& load_details) override; + + private: + base::RepeatingClosure closure_; + + DISALLOW_COPY_AND_ASSIGN(BrowserListSessionServiceWebStateObserver); +}; + +BrowserListSessionServiceWebStateObserver:: + BrowserListSessionServiceWebStateObserver( + const base::RepeatingClosure& closure) + : WebStateObserver(), closure_(closure) { + DCHECK(!closure_.is_null()); +} + +BrowserListSessionServiceWebStateObserver:: + ~BrowserListSessionServiceWebStateObserver() = default; + +void BrowserListSessionServiceWebStateObserver::ObserveWebState( + web::WebState* web_state) { + WebStateObserver::Observe(web_state); +} + +void BrowserListSessionServiceWebStateObserver::NavigationItemCommitted( + const web::LoadCommittedDetails& load_details) { + closure_.Run(); +} + +// BrowserListSessionServiceWebStateListObserver observes a WebStateList and +// invokes |closure| when the active WebState changes or a navigation item is +// committed in the active WebState. +class BrowserListSessionServiceWebStateListObserver + : public WebStateListObserver { + public: + BrowserListSessionServiceWebStateListObserver( + WebStateList* web_state_list, + const base::RepeatingClosure& closure); + ~BrowserListSessionServiceWebStateListObserver() override; + + // WebStateListObserver implementation. + void WebStateActivatedAt(WebStateList* web_state_list, + web::WebState* old_web_state, + web::WebState* new_web_state, + int active_index, + bool user_action) override; + + private: + WebStateList* web_state_list_; + base::RepeatingClosure closure_; + BrowserListSessionServiceWebStateObserver observer_; + + DISALLOW_COPY_AND_ASSIGN(BrowserListSessionServiceWebStateListObserver); +}; + +BrowserListSessionServiceWebStateListObserver:: + BrowserListSessionServiceWebStateListObserver( + WebStateList* web_state_list, + const base::RepeatingClosure& closure) + : web_state_list_(web_state_list), closure_(closure), observer_(closure) { + DCHECK(!closure_.is_null()); + web_state_list_->AddObserver(this); + if (web_state_list_->active_index() != WebStateList::kInvalidIndex) { + WebStateActivatedAt(web_state_list_, nullptr, + web_state_list_->GetActiveWebState(), + web_state_list_->active_index(), false); + } +} + +BrowserListSessionServiceWebStateListObserver:: + ~BrowserListSessionServiceWebStateListObserver() { + web_state_list_->RemoveObserver(this); +} + +void BrowserListSessionServiceWebStateListObserver::WebStateActivatedAt( + WebStateList* web_state_list, + web::WebState* old_web_state, + web::WebState* new_web_state, + int active_index, + bool user_action) { + if (old_web_state) + closure_.Run(); + observer_.ObserveWebState(new_web_state); +} + +// BrowserListSessionServiceBrowserListObserver observes a BrowserList and +// invokes |closure| then the active WebState changes in any of the Browsers' +// WebStates or a navigation item is committed in one of the active WebStates. +class BrowserListSessionServiceBrowserListObserver + : public BrowserListObserver { + public: + BrowserListSessionServiceBrowserListObserver( + BrowserList* browser_list, + const base::RepeatingClosure& closure); + ~BrowserListSessionServiceBrowserListObserver() override; + + // BrowserListObserver implementation. + void OnBrowserCreated(BrowserList* browser_list, Browser* browser) override; + void OnBrowserRemoved(BrowserList* browser_list, Browser* browser) override; + + private: + BrowserList* browser_list_; + base::RepeatingClosure closure_; + std::map<Browser*, std::unique_ptr<WebStateListObserver>> observers_; + + DISALLOW_COPY_AND_ASSIGN(BrowserListSessionServiceBrowserListObserver); +}; + +BrowserListSessionServiceBrowserListObserver:: + BrowserListSessionServiceBrowserListObserver( + BrowserList* browser_list, + const base::RepeatingClosure& closure) + : browser_list_(browser_list), closure_(closure) { + DCHECK(!closure_.is_null()); + for (int index = 0; index < browser_list_->count(); ++index) + OnBrowserCreated(browser_list_, browser_list_->GetBrowserAtIndex(index)); + browser_list_->AddObserver(this); +} + +BrowserListSessionServiceBrowserListObserver:: + ~BrowserListSessionServiceBrowserListObserver() { + browser_list_->RemoveObserver(this); +} + +void BrowserListSessionServiceBrowserListObserver::OnBrowserCreated( + BrowserList* browser_list, + Browser* browser) { + DCHECK(browser); + DCHECK_EQ(browser_list, browser_list_); + DCHECK(observers_.find(browser) == observers_.end()); + observers_.insert(std::make_pair( + browser, base::MakeUnique<BrowserListSessionServiceWebStateListObserver>( + &browser->web_state_list(), closure_))); +} + +void BrowserListSessionServiceBrowserListObserver::OnBrowserRemoved( + BrowserList* browser_list, + Browser* browser) { + DCHECK(browser); + DCHECK_EQ(browser_list, browser_list_); + DCHECK(observers_.find(browser) != observers_.end()); + observers_.erase(browser); +} + +} // namespace + +BrowserListSessionServiceImpl::BrowserListSessionServiceImpl( + BrowserList* browser_list, + NSString* session_directory, + SessionServiceIOS* session_service, + const CreateWebStateCallback& create_web_state) + : browser_list_(browser_list), + session_directory_([session_directory copy]), + session_service_(session_service), + create_web_state_(create_web_state) { + DCHECK(browser_list_); + DCHECK(session_directory_); + DCHECK(session_service_); + DCHECK(create_web_state_); + // It is safe to use base::Unretained as the closure is indirectly owned by + // the BrowserListSessionServiceImpl instance and will be deleted before it. + observer_ = base::MakeUnique<BrowserListSessionServiceBrowserListObserver>( + browser_list, + base::BindRepeating(&BrowserListSessionServiceImpl::ScheduleSaveSession, + base::Unretained(this), false)); +} + +BrowserListSessionServiceImpl::~BrowserListSessionServiceImpl() = default; + +bool BrowserListSessionServiceImpl::RestoreSession() { + DCHECK(browser_list_) << "RestoreSession called after Shutdown."; + SessionIOS* session = + [session_service_ loadSessionFromDirectory:session_directory_]; + if (!session) + return false; + + DCHECK_LE(session.sessionWindows.count, static_cast<NSUInteger>(INT_MAX)); + for (NSUInteger index = 0; index < session.sessionWindows.count; ++index) { + Browser* browser = + static_cast<int>(index) < browser_list_->count() + ? browser_list_->GetBrowserAtIndex(static_cast<int>(index)) + : browser_list_->CreateNewBrowser(); + + SessionWindowIOS* session_window = session.sessionWindows[index]; + if (!session_window.sessions.count) + continue; + + WebStateList& web_state_list = browser->web_state_list(); + const int old_count = web_state_list.count(); + DeserializeWebStateList(&web_state_list, session_window, create_web_state_); + DCHECK_GT(web_state_list.count(), old_count); + + // If there was a single tab open without any navigation, then close it + // after restoring the tabs. + if (old_count != 1) + continue; + + web::WebState* web_state = web_state_list.GetWebStateAt(0); + web::NavigationManager* navigation_manager = + web_state->GetNavigationManager(); + + if (navigation_manager->CanGoBack()) + continue; + + web::NavigationItem* navigation_item = + navigation_manager->GetLastCommittedItem(); + if (!navigation_item) + continue; + + if (navigation_item->GetURL() != kChromeUINewTabURL) + continue; + + web_state_list.CloseWebStateAt(0); + } + + return true; +} + +void BrowserListSessionServiceImpl::ScheduleLastSessionDeletion() { + DCHECK(browser_list_) << "ScheduleLastSessionDeletion called after Shutdown."; + [session_service_ deleteLastSessionFileInDirectory:session_directory_]; +} + +void BrowserListSessionServiceImpl::ScheduleSaveSession(bool immediately) { + DCHECK(browser_list_) << "ScheduleSaveSession called after Shutdown."; + DCHECK_GE(browser_list_->count(), 0); + const int count = browser_list_->count(); + NSMutableArray<SessionWindowIOS*>* windows = + [NSMutableArray arrayWithCapacity:static_cast<NSUInteger>(count)]; + for (int index = 0; index < count; ++index) { + Browser* browser = browser_list_->GetBrowserAtIndex(index); + [windows addObject:SerializeWebStateList(&browser->web_state_list())]; + } + + [session_service_ saveSession:[[SessionIOS alloc] initWithWindows:windows] + directory:session_directory_ + immediately:immediately]; +} + +void BrowserListSessionServiceImpl::Shutdown() { + // Stop observing the BrowserList before it is destroyed (BrowserList is a + // base::SupportsUserData::Data attached to ChromeBrowserState so it will + // be destroyed after the KeyedService two-stage shutdown). + browser_list_ = nullptr; + observer_.reset(); +}
diff --git a/ios/web/navigation/window_location_inttest.mm b/ios/web/navigation/window_location_inttest.mm index efd90c2c..d6821a5 100644 --- a/ios/web/navigation/window_location_inttest.mm +++ b/ios/web/navigation/window_location_inttest.mm
@@ -205,7 +205,7 @@ #if TARGET_IPHONE_SIMULATOR #define MAYBE_WindowLocationReload WindowLocationReload #else -#define MAYBE_WindowLocationReload FLAKY_WindowLocationReload +#define MAYBE_WindowLocationReload DISABLED_WindowLocationReload #endif // TODO(crbug.com/721465): Enable this test on device. TEST_F(WindowLocationTest, MAYBE_WindowLocationReload) {
diff --git a/ios/web/public/origin_util_unittest.mm b/ios/web/public/origin_util_unittest.mm index 723ebf7..79cae2b0 100644 --- a/ios/web/public/origin_util_unittest.mm +++ b/ios/web/public/origin_util_unittest.mm
@@ -6,7 +6,7 @@ #import <WebKit/WebKit.h> -#include "base/mac/objc_release_properties.h" +#import "base/mac/objc_property_releaser.h" #import "base/mac/scoped_nsobject.h" #include "testing/gtest/include/gtest/gtest.h" #include "url/gurl.h" @@ -19,13 +19,17 @@ @property(nonatomic) NSInteger port; @end -@implementation WKSecurityOriginStub +@implementation WKSecurityOriginStub { + base::mac::ObjCPropertyReleaser _propertyReleaser; +} @synthesize protocol = _protocol; @synthesize host = _host; @synthesize port = _port; -- (void)dealloc { - base::mac::ReleaseProperties(self); - [super dealloc]; +- (instancetype)init { + if (self = [super init]) { + _propertyReleaser.Init(self, [WKSecurityOriginStub class]); + } + return self; } @end
diff --git a/ios/web/public/test/test_web_thread_bundle.h b/ios/web/public/test/test_web_thread_bundle.h index dc3497c..49eb03fa 100644 --- a/ios/web/public/test/test_web_thread_bundle.h +++ b/ios/web/public/test/test_web_thread_bundle.h
@@ -12,16 +12,16 @@ // first member variable in test classes, so it is destroyed last, and the test // threads always exist from the perspective of other classes. // -// By default, all of the created TestWebThreads and the task scheduler will -// be backed by a single shared MessageLoop. If a test truly needs separate -// threads, it can do so by passing the appropriate combination of option values -// during the TestWebThreadBundle construction. +// By default, all of the created TestWebThreads will be backed by a single +// shared MessageLoop. If a test truly needs separate threads, it can do so by +// passing the appropriate combination of option values during the +// TestWebThreadBundle construction. // -// To synchronously run tasks posted to task scheduler or to TestWebThreads -// that use the shared MessageLoop, call RunLoop::Run/RunUntilIdle() on the -// thread where the TestWebThreadBundle lives. The destructor of -// TestWebThreadBundle runs remaining TestWebThreads tasks, remaining -// blocking pool tasks, and remaining BLOCK_SHUTDOWN task scheduler tasks. +// To synchronously run tasks posted to TestWebThreads that use the shared +// MessageLoop, call RunLoop::Run/RunUntilIdle() on the thread where the +// TestWebThreadBundle lives. The destructor of TestWebThreadBundle runs +// remaining TestWebThreads tasks, remaining blocking pool tasks, and remaining +// BLOCK_SHUTDOWN task scheduler tasks. // // Some tests using the IO thread expect a MessageLoopForIO. Passing // IO_MAINLOOP will use a MessageLoopForIO for the main MessageLoop. @@ -35,7 +35,6 @@ class MessageLoop; namespace test { class ScopedAsyncTaskScheduler; -class ScopedTaskScheduler; } // namespace test } // namespace base @@ -54,7 +53,6 @@ REAL_DB_THREAD = 1 << 1, REAL_FILE_THREAD = 1 << 2, REAL_IO_THREAD = 1 << 3, - REAL_TASK_SCHEDULER = 1 << 4, }; TestWebThreadBundle(); @@ -68,7 +66,6 @@ std::unique_ptr<base::MessageLoop> message_loop_; std::unique_ptr<base::test::ScopedAsyncTaskScheduler> scoped_async_task_scheduler_; - std::unique_ptr<base::test::ScopedTaskScheduler> scoped_task_scheduler_; std::unique_ptr<TestWebThread> ui_thread_; std::unique_ptr<TestWebThread> db_thread_; std::unique_ptr<TestWebThread> file_thread_;
diff --git a/ios/web/test/test_web_thread_bundle.cc b/ios/web/test/test_web_thread_bundle.cc index 14eb656..e6d776e4 100644 --- a/ios/web/test/test_web_thread_bundle.cc +++ b/ios/web/test/test_web_thread_bundle.cc
@@ -8,7 +8,6 @@ #include "base/message_loop/message_loop.h" #include "base/run_loop.h" #include "base/test/scoped_async_task_scheduler.h" -#include "base/test/scoped_task_scheduler.h" #include "ios/web/public/test/test_web_thread.h" #include "ios/web/web_thread_impl.h" @@ -53,7 +52,6 @@ base::RunLoop().RunUntilIdle(); scoped_async_task_scheduler_.reset(); - scoped_task_scheduler_.reset(); } void TestWebThreadBundle::Init(int options) { @@ -65,13 +63,8 @@ ui_thread_.reset(new TestWebThread(WebThread::UI, message_loop_.get())); - if (options & REAL_TASK_SCHEDULER) { - scoped_async_task_scheduler_ = - base::MakeUnique<base::test::ScopedAsyncTaskScheduler>(); - } else { - scoped_task_scheduler_ = - base::MakeUnique<base::test::ScopedTaskScheduler>(message_loop_.get()); - } + scoped_async_task_scheduler_ = + base::MakeUnique<base::test::ScopedAsyncTaskScheduler>(); if (options & TestWebThreadBundle::REAL_DB_THREAD) { db_thread_.reset(new TestWebThread(WebThread::DB));
diff --git a/ios/web/web_state/ui/crw_web_controller.mm b/ios/web/web_state/ui/crw_web_controller.mm index 1322901..894043784 100644 --- a/ios/web/web_state/ui/crw_web_controller.mm +++ b/ios/web/web_state/ui/crw_web_controller.mm
@@ -25,7 +25,7 @@ #import "base/mac/bind_objc_block.h" #include "base/mac/bundle_locations.h" #include "base/mac/foundation_util.h" -#include "base/mac/objc_release_properties.h" +#import "base/mac/objc_property_releaser.h" #include "base/mac/scoped_cftyperef.h" #import "base/mac/scoped_nsobject.h" #include "base/memory/ptr_util.h" @@ -216,7 +216,10 @@ // A container object for any navigation information that is only available // during pre-commit delegate callbacks, and thus must be held until the // navigation commits and the informatino can be used. -@interface CRWWebControllerPendingNavigationInfo : NSObject +@interface CRWWebControllerPendingNavigationInfo : NSObject { + base::mac::ObjCPropertyReleaser + _propertyReleaser_CRWWebControllerPendingNavigationInfo; +} // The referrer for the page. @property(nonatomic, copy) NSString* referrer; // The MIME type for the page. @@ -241,16 +244,12 @@ - (instancetype)init { if ((self = [super init])) { + _propertyReleaser_CRWWebControllerPendingNavigationInfo.Init( + self, [CRWWebControllerPendingNavigationInfo class]); _navigationType = WKNavigationTypeOther; } return self; } - -- (void)dealloc { - base::mac::ReleaseProperties(self); - [super dealloc]; -} - @end @interface CRWWebController ()<CRWContextMenuDelegate,
diff --git a/mojo/public/cpp/system/wait_set.cc b/mojo/public/cpp/system/wait_set.cc index 1728f81b..75ce93e 100644 --- a/mojo/public/cpp/system/wait_set.cc +++ b/mojo/public/cpp/system/wait_set.cc
@@ -271,12 +271,9 @@ Context* context) { base::AutoLock lock(lock_); - // This could be a cancellation notification following an explicit - // RemoveHandle(), in which case we really don't care and don't want to - // add it to the ready set. Only update and signal if that's not the case. - if (!handle_to_context_.count(handle)) { - DCHECK_EQ(MOJO_RESULT_CANCELLED, result); - } else { + // This notification may have raced with RemoveHandle() from another thread. + // We only signal the WaitSet if that's not the case. + if (handle_to_context_.count(handle)) { ready_handles_[handle] = {result, signals_state}; handle_event_.Signal(); }
diff --git a/net/http/http_stream_factory_impl.cc b/net/http/http_stream_factory_impl.cc index 2579933..669f04f 100644 --- a/net/http/http_stream_factory_impl.cc +++ b/net/http/http_stream_factory_impl.cc
@@ -194,6 +194,8 @@ void HttpStreamFactoryImpl::PreconnectStreams( int num_streams, const HttpRequestInfo& request_info) { + DCHECK(request_info.url.is_valid()); + AddJobControllerCountToHistograms(); SSLConfig server_ssl_config;
diff --git a/remoting/client/chromoting_client.cc b/remoting/client/chromoting_client.cc index 8029477..ced714a 100644 --- a/remoting/client/chromoting_client.cc +++ b/remoting/client/chromoting_client.cc
@@ -40,6 +40,8 @@ } ChromotingClient::~ChromotingClient() { + DCHECK(thread_checker_.CalledOnValidThread()); + if (signal_strategy_) signal_strategy_->RemoveListener(this); }
diff --git a/remoting/client/client_telemetry_logger.cc b/remoting/client/client_telemetry_logger.cc index 908a527..3240c69 100644 --- a/remoting/client/client_telemetry_logger.cc +++ b/remoting/client/client_telemetry_logger.cc
@@ -36,7 +36,9 @@ ChromotingEvent::Mode mode) : mode_(mode), log_writer_(log_writer) {} -ClientTelemetryLogger::~ClientTelemetryLogger() {} +ClientTelemetryLogger::~ClientTelemetryLogger() { + DCHECK(thread_checker_.CalledOnValidThread()); +} void ClientTelemetryLogger::SetHostInfo(const std::string& host_version, ChromotingEvent::Os host_os,
diff --git a/remoting/client/display/fake_canvas.cc b/remoting/client/display/fake_canvas.cc index 167fe36b..fb7fde6b 100644 --- a/remoting/client/display/fake_canvas.cc +++ b/remoting/client/display/fake_canvas.cc
@@ -8,7 +8,9 @@ FakeCanvas::FakeCanvas() : weak_factory_(this) {} -FakeCanvas::~FakeCanvas() {} +FakeCanvas::~FakeCanvas() { + DCHECK(thread_checker_.CalledOnValidThread()); +} void FakeCanvas::Clear() {}
diff --git a/remoting/client/display/gl_cursor.cc b/remoting/client/display/gl_cursor.cc index 113de25..cabb758ec 100644 --- a/remoting/client/display/gl_cursor.cc +++ b/remoting/client/display/gl_cursor.cc
@@ -20,7 +20,9 @@ GlCursor::GlCursor() : weak_factory_(this) {} -GlCursor::~GlCursor() {} +GlCursor::~GlCursor() { + DCHECK(thread_checker_.CalledOnValidThread()); +} void GlCursor::SetCursorShape(const protocol::CursorShapeInfo& cursor_shape) { int data_size = cursor_shape.width() * cursor_shape.height() *
diff --git a/remoting/client/display/gl_cursor_feedback.cc b/remoting/client/display/gl_cursor_feedback.cc index 97804211..0e6fbfb 100644 --- a/remoting/client/display/gl_cursor_feedback.cc +++ b/remoting/client/display/gl_cursor_feedback.cc
@@ -45,7 +45,9 @@ GlCursorFeedback::GlCursorFeedback() : weak_factory_(this) {} -GlCursorFeedback::~GlCursorFeedback() {} +GlCursorFeedback::~GlCursorFeedback() { + DCHECK(thread_checker_.CalledOnValidThread()); +} void GlCursorFeedback::SetCanvas(base::WeakPtr<Canvas> canvas) { if (!canvas) {
diff --git a/remoting/client/display/gl_desktop.cc b/remoting/client/display/gl_desktop.cc index 41cb4632..9362bd3 100644 --- a/remoting/client/display/gl_desktop.cc +++ b/remoting/client/display/gl_desktop.cc
@@ -59,7 +59,9 @@ GlDesktop::GlDesktop() : weak_factory_(this) {} -GlDesktop::~GlDesktop() {} +GlDesktop::~GlDesktop() { + DCHECK(thread_checker_.CalledOnValidThread()); +} void GlDesktop::SetCanvas(base::WeakPtr<Canvas> canvas) { last_desktop_size_.set(0, 0);
diff --git a/remoting/client/display/gl_renderer.cc b/remoting/client/display/gl_renderer.cc index 8b2ee23..2913ff3 100644 --- a/remoting/client/display/gl_renderer.cc +++ b/remoting/client/display/gl_renderer.cc
@@ -33,7 +33,9 @@ thread_checker_.DetachFromThread(); } -GlRenderer::~GlRenderer() {} +GlRenderer::~GlRenderer() { + DCHECK(thread_checker_.CalledOnValidThread()); +} void GlRenderer::SetDelegate(base::WeakPtr<GlRendererDelegate> delegate) { DCHECK(!delegate_);
diff --git a/remoting/client/plugin/pepper_video_renderer_2d.cc b/remoting/client/plugin/pepper_video_renderer_2d.cc index 4a605cb..730ddf6 100644 --- a/remoting/client/plugin/pepper_video_renderer_2d.cc +++ b/remoting/client/plugin/pepper_video_renderer_2d.cc
@@ -58,7 +58,9 @@ callback_factory_(this), weak_factory_(this) {} -PepperVideoRenderer2D::~PepperVideoRenderer2D() {} +PepperVideoRenderer2D::~PepperVideoRenderer2D() { + DCHECK(thread_checker_.CalledOnValidThread()); +} void PepperVideoRenderer2D::SetPepperContext( pp::Instance* instance,
diff --git a/remoting/client/software_video_renderer.cc b/remoting/client/software_video_renderer.cc index 52ff346..11504f66 100644 --- a/remoting/client/software_video_renderer.cc +++ b/remoting/client/software_video_renderer.cc
@@ -57,6 +57,8 @@ } SoftwareVideoRenderer::~SoftwareVideoRenderer() { + DCHECK(thread_checker_.CalledOnValidThread()); + if (decoder_) decode_task_runner_->DeleteSoon(FROM_HERE, decoder_.release()); }
diff --git a/remoting/ios/display/gl_demo_screen.mm b/remoting/ios/display/gl_demo_screen.mm index c293fe5c..738d1a6 100644 --- a/remoting/ios/display/gl_demo_screen.mm +++ b/remoting/ios/display/gl_demo_screen.mm
@@ -35,7 +35,9 @@ // integration. This will draw an expanding checkerboard pattern to the screen. GlDemoScreen::GlDemoScreen() : weak_factory_(this) {} -GlDemoScreen::~GlDemoScreen() {} +GlDemoScreen::~GlDemoScreen() { + DCHECK(thread_checker_.CalledOnValidThread()); +} void GlDemoScreen::SetCanvas(base::WeakPtr<Canvas> canvas) { canvas_ = canvas;
diff --git a/testing/variations/fieldtrial_testing_config.json b/testing/variations/fieldtrial_testing_config.json index 54ba46d..d3a759c7 100644 --- a/testing/variations/fieldtrial_testing_config.json +++ b/testing/variations/fieldtrial_testing_config.json
@@ -3213,21 +3213,6 @@ ] } ], - "VrShell": [ - { - "platforms": [ - "android" - ], - "experiments": [ - { - "name": "Enabled", - "enable_features": [ - "VrShell" - ] - } - ] - } - ], "WebApkGooglePlay": [ { "platforms": [
diff --git a/third_party/WebKit/LayoutTests/TestExpectations b/third_party/WebKit/LayoutTests/TestExpectations index cd69f10..9b856ba8 100644 --- a/third_party/WebKit/LayoutTests/TestExpectations +++ b/third_party/WebKit/LayoutTests/TestExpectations
@@ -42,6 +42,7 @@ crbug.com/596780 virtual/spv2/compositing/framesets/composited-frame-alignment.html [ Pass ] crbug.com/596780 virtual/spv2/compositing/geometry/outline-change.html [ Pass ] crbug.com/600618 virtual/spv2/svg/custom/object-current-scale.html [ Pass ] +crbug.com/682074 virtual/display_list_2d_canvas/fast/canvas/canvas-text-alignment.html [ NeedsRebaseline ] # Re-add this once it rebaselines. # crbug.com/600618 virtual/spv2/svg/custom/object-sizing-explicit-height.xhtml [ Pass ]
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/editing/dnd/events/relatedTarget-attribute-manual.html b/third_party/WebKit/LayoutTests/external/wpt/html/editing/dnd/events/relatedTarget-attribute-manual.html new file mode 100644 index 0000000..c5a897d --- /dev/null +++ b/third_party/WebKit/LayoutTests/external/wpt/html/editing/dnd/events/relatedTarget-attribute-manual.html
@@ -0,0 +1,65 @@ +<!doctype html> +<html> + <head> + <title>relatedTarget attribute for dragenter and dragleave events</title> + <meta name="viewport" content="width=device-width"> + <script src="/resources/testharness.js"></script> + <script src="/resources/testharnessreport.js"></script> + <style> + #outerdiv { + padding: 50px; + background: blue; + } + #innerdiv { + width:200px; + height:100px; + background: green; + } + </style> + <script> + var drag_test = async_test("dragenter and dragleave are correctly fired."); + var got_dragenter = false; + var got_dragleave = false; + function run() { + var draggable = document.getElementById("draggable"); + var innerdiv = document.getElementById("innerdiv"); + draggable.addEventListener("dragstart", (e) => { + e.dataTransfer.setData("text", draggable.innerHTML); + }); + innerdiv.addEventListener("dragenter", (e) => { + if (!got_dragenter) { + test(function() { + assert_equals(e.relatedTarget.id, "outerdiv", "dragenter event should have the correct relatedTarget."); + }, "dragenter event should have the correct relatedTarget."); + got_dragenter = true; + } + }); + innerdiv.addEventListener("dragleave", (e) => { + if (!got_dragleave) { + test(function() { + assert_equals(e.relatedTarget.id, "outerdiv", "dragleave event should have the correct relatedTarget."); + }, "dragleave event should have the correct relatedTarget."); + got_dragleave = true; + if (got_dragenter) + drag_test.done(); + } + }); + } + </script> + </head> + <body onload="run()"> + <h1>Drag & Drop: relatedTarget attribute for dragenter and dragleave events</h1> + <h2 id="pointerTypeDescription"></h2> + <h4>Test Description: + <ol> + <li>Drag the text into the green box.</li> + <li>Without releasing the drag, drag the text out of the green box.</li> + </ol> + </h4> + <br> + <div id="draggable" draggable="true">Drag this text</br>over the green box</div> + <div id="outerdiv"> + <div id="innerdiv"></div> + </div> + </body> +</html>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/semantics/scripting-1/the-script-element/module/script-for-event.html b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/scripting-1/the-script-element/module/script-for-event.html new file mode 100644 index 0000000..e3b8e15 --- /dev/null +++ b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/scripting-1/the-script-element/module/script-for-event.html
@@ -0,0 +1,93 @@ +<!DOCTYPE html> +<title>Module scripts with for and event attributes</title> +<link rel="author" title="Matheus Kerschbaum" href="mailto:matjk7@gmail.com"> +<link rel="author" title="Ms2ger" href="mailto:ms2ger@gmail.com"> +<link rel="help" href="https://html.spec.whatwg.org/multipage/#prepare-a-script"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<div id="log"></div> +<script> +var expected = [ + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, +]; +var run = expected.map(function() { return false }); +</script> +<script for="wİndow" event="onload" type="module"> +run[0] = true; +</script> +<script for="window" event="onload x" type="module"> +run[1] = true; +</script> +<script for="window" event="onload(x" type="module"> +run[2] = true; +</script> +<script for="window" event="onload(x)" type="module"> +run[3] = true; +</script> +<script for="window" event="onclick" type="module"> +run[4] = true; +</script> +<script for="" event="onload" type="module"> +run[5] = true; +</script> +<script for="window" event="" type="module"> +run[6] = true; +</script> +<script for="" event="" type="module"> +run[7] = true; +</script> +<script for=" window" event="onload" type="module"> +run[8] = true; +</script> +<script for="window " event="onload" type="module"> +run[9] = true; +</script> +<script for="window" event=" onload" type="module"> +run[10] = true; +</script> +<script for="window" event="onload " type="module"> +run[11] = true; +</script> +<script for=" window " event=" onload " type="module"> +run[12] = true; +</script> +<script for=" window " event=" onload() " type="module"> +run[13] = true; +</script> +<script for="object" event="handler" type="module"> +run[14] = true; +</script> +<script event="handler" type="module"> +run[15] = true; +</script> +<script for="object" type="module"> +run[16] = true; +</script> +<script type="module"> +test(function() { + for (var i = 0; i < run.length; ++i) { + test(function() { + var script = document.querySelectorAll("script[for], script[event]")[i]; + assert_equals(run[i], expected[i], + "script for=" + format_value(script.getAttribute("for")) + + " event=" + format_value(script.getAttribute("event"))); + }, "Script " + i); + } +}); +</script>
diff --git a/third_party/WebKit/LayoutTests/external/wpt_automation/html/editing/dnd/events/relatedTarget-attribute-manual-automation.js b/third_party/WebKit/LayoutTests/external/wpt_automation/html/editing/dnd/events/relatedTarget-attribute-manual-automation.js new file mode 100644 index 0000000..4bed7c9 --- /dev/null +++ b/third_party/WebKit/LayoutTests/external/wpt_automation/html/editing/dnd/events/relatedTarget-attribute-manual-automation.js
@@ -0,0 +1,6 @@ +importAutomationScript('/pointerevents/pointerevent_common_input.js'); + +function inject_input() { + return mouseDragAndDropInTargets(['#draggable', '#outerdiv', '#innerdiv', '#outerdiv']); +} +
diff --git a/third_party/WebKit/LayoutTests/external/wpt_automation/pointerevents/pointerevent_common_input.js b/third_party/WebKit/LayoutTests/external/wpt_automation/pointerevents/pointerevent_common_input.js index b738cb6..d8b682c 100644 --- a/third_party/WebKit/LayoutTests/external/wpt_automation/pointerevents/pointerevent_common_input.js +++ b/third_party/WebKit/LayoutTests/external/wpt_automation/pointerevents/pointerevent_common_input.js
@@ -440,6 +440,34 @@ }); } +// Drag and drop actions +function mouseDragAndDropInTargets(targetSelectorList) { + return new Promise(function(resolve, reject) { + if (window.eventSender) { + scrollPageIfNeeded(targetSelectorList[0], document); + var target = document.querySelector(targetSelectorList[0]); + var targetRect = target.getBoundingClientRect(); + var xPosition = targetRect.left + boundaryOffset; + var yPosition = targetRect.top + boundaryOffset; + eventSender.mouseMoveTo(xPosition, yPosition); + eventSender.mouseDown(); + eventSender.leapForward(100); + for (var i = 1; i < targetSelectorList.length; i++) { + scrollPageIfNeeded(targetSelectorList[i], document); + target = document.querySelector(targetSelectorList[i]); + targetRect = target.getBoundingClientRect(); + xPosition = targetRect.left + boundaryOffset; + yPosition = targetRect.top + boundaryOffset; + eventSender.mouseMoveTo(xPosition, yPosition); + } + eventSender.mouseUp(); + resolve(); + } else { + reject(); + } + }); +} + // Keyboard inputs. function keyboardScroll(direction) { return new Promise(function(resolve, reject) {
diff --git a/third_party/WebKit/LayoutTests/resources/testharnessreport.js b/third_party/WebKit/LayoutTests/resources/testharnessreport.js index 28559fd3..3c4fa649 100644 --- a/third_party/WebKit/LayoutTests/resources/testharnessreport.js +++ b/third_party/WebKit/LayoutTests/resources/testharnessreport.js
@@ -118,7 +118,8 @@ src = automationPath + '/fullscreen/auto-click.js'; } else if (pathAndBase.startsWith('/pointerevents/') || pathAndBase.startsWith('/uievents/') - || pathAndBase.startsWith('/pointerlock/')) { + || pathAndBase.startsWith('/pointerlock/') + || pathAndBase.startsWith('/html/')) { // Per-test automation scripts. src = automationPath + pathAndBase + '-automation.js'; } else {
diff --git a/third_party/WebKit/LayoutTests/webaudio/AudioParam/audioparam-nominal-range.html b/third_party/WebKit/LayoutTests/webaudio/AudioParam/audioparam-nominal-range.html index 47dc585b..edda37e 100644 --- a/third_party/WebKit/LayoutTests/webaudio/AudioParam/audioparam-nominal-range.html +++ b/third_party/WebKit/LayoutTests/webaudio/AudioParam/audioparam-nominal-range.html
@@ -189,7 +189,7 @@ args: [1, 1, sampleRate], }, { creator: "createIIRFilter", - args: [[1,2],[3,4]] + args: [[1,2],[1, .9]] }, { creator: "createWaveShaper", args: [],
diff --git a/third_party/WebKit/LayoutTests/webaudio/IIRFilter/iir-unstable-expected.txt b/third_party/WebKit/LayoutTests/webaudio/IIRFilter/iir-unstable-expected.txt new file mode 100644 index 0000000..9def0db --- /dev/null +++ b/third_party/WebKit/LayoutTests/webaudio/IIRFilter/iir-unstable-expected.txt
@@ -0,0 +1,10 @@ +CONSOLE ERROR: line 39: [audit.js] this test requires the explicit comparison with the expected result when it runs with run-webkit-tests. +CONSOLE WARNING: line 18: Unstable IIRFilter with feedback coefficients: [1, 1.1] +This is a testharness.js-based test. +PASS # AUDIT TASK RUNNER STARTED. +PASS > [unstable] +PASS Creating unstable IIR filter with createIIRFilter([1], [1, 1.1]) did not throw an exception. +PASS < [unstable] All assertions passed. (total 1 assertions) +PASS # AUDIT TASK RUNNER FINISHED: 1 tasks ran successfully. +Harness: the test ran to completion. +
diff --git a/third_party/WebKit/LayoutTests/webaudio/IIRFilter/iir-unstable.html b/third_party/WebKit/LayoutTests/webaudio/IIRFilter/iir-unstable.html new file mode 100644 index 0000000..11fb1b7c --- /dev/null +++ b/third_party/WebKit/LayoutTests/webaudio/IIRFilter/iir-unstable.html
@@ -0,0 +1,27 @@ +<!doctype html> +<html> + <head> + <title>Test Unstable IIR Filter</title> + <script src="../../resources/testharness.js"></script> + <script src="../../resources/testharnessreport.js"></script> + <script src="../resources/audit-util.js"></script> + <script src="../resources/audit.js"></script> + </head> + + <body> + <script> + let audit = Audit.createTaskRunner({requireResultFile: true}); + + audit.define('unstable', (task, should) => { + let context = new OfflineAudioContext(1, 1, 8000); + should(() => { + context.createIIRFilter([1], [1, 1.1]); + }, 'Creating unstable IIR filter with createIIRFilter([1], [1, 1.1])').notThrow(); + + task.done(); + }); + + audit.run(); + </script> + </body> +</html>
diff --git a/third_party/WebKit/Source/bindings/core/v8/ScriptPromiseResolver.cpp b/third_party/WebKit/Source/bindings/core/v8/ScriptPromiseResolver.cpp index fd86dcf..f2bdd5d 100644 --- a/third_party/WebKit/Source/bindings/core/v8/ScriptPromiseResolver.cpp +++ b/third_party/WebKit/Source/bindings/core/v8/ScriptPromiseResolver.cpp
@@ -76,7 +76,7 @@ if (state_ == kResolving) { resolver_.Resolve(value_.NewLocal(script_state_->GetIsolate())); } else { - ASSERT(state_ == kRejecting); + DCHECK_EQ(state_, kRejecting); resolver_.Reject(value_.NewLocal(script_state_->GetIsolate())); } }
diff --git a/third_party/WebKit/Source/bindings/core/v8/ScriptPromiseResolver.h b/third_party/WebKit/Source/bindings/core/v8/ScriptPromiseResolver.h index 01136b79..8085848d 100644 --- a/third_party/WebKit/Source/bindings/core/v8/ScriptPromiseResolver.h +++ b/third_party/WebKit/Source/bindings/core/v8/ScriptPromiseResolver.h
@@ -127,7 +127,7 @@ ScriptState::Scope scope(script_state_.Get()); - // Calling ToV8 in a ScriptForbiddenScope will trigger a RELEASE_ASSERT and + // Calling ToV8 in a ScriptForbiddenScope will trigger a CHECK and // cause a crash. ToV8 just invokes a constructor for wrapper creation, // which is safe (no author script can be run). Adding AllowUserAgentScript // directly inside createWrapper could cause a perf impact (calling @@ -145,7 +145,7 @@ KeepAliveWhilePending(); return; } - // TODO(esprehn): This is a hack, instead we should RELEASE_ASSERT that + // TODO(esprehn): This is a hack, instead we should CHECK that // script is allowed, and v8 should be running the entry hooks below and // crashing if script is forbidden. We should then audit all users of // ScriptPromiseResolver and the related specs and switch to an async
diff --git a/third_party/WebKit/Source/bindings/core/v8/ScriptValue.cpp b/third_party/WebKit/Source/bindings/core/v8/ScriptValue.cpp index e7e389e..df7f20c 100644 --- a/third_party/WebKit/Source/bindings/core/v8/ScriptValue.cpp +++ b/third_party/WebKit/Source/bindings/core/v8/ScriptValue.cpp
@@ -47,7 +47,7 @@ // Probably this could be: // if (&script_state_->world() == &DOMWrapperWorld::current(isolate())) // return v8::Local<v8::Value>(); - // instead of triggering RELEASE_ASSERT. + // instead of triggering CHECK. CHECK_EQ(&script_state_->World(), &DOMWrapperWorld::Current(GetIsolate())); return value_->NewLocal(GetIsolate()); }
diff --git a/third_party/WebKit/Source/build/scripts/templates/CSSPropertyMetadata.cpp.tmpl b/third_party/WebKit/Source/build/scripts/templates/CSSPropertyMetadata.cpp.tmpl index 219fbc6..a89634e9 100644 --- a/third_party/WebKit/Source/build/scripts/templates/CSSPropertyMetadata.cpp.tmpl +++ b/third_party/WebKit/Source/build/scripts/templates/CSSPropertyMetadata.cpp.tmpl
@@ -65,7 +65,7 @@ if (unresolvedProperty == CSSPropertyVariable) return true; - ASSERT(unresolvedProperty == CSSPropertyApplyAtRule); + DCHECK_EQ(unresolvedProperty, CSSPropertyApplyAtRule); return RuntimeEnabledFeatures::cssApplyAtRulesEnabled(); }
diff --git a/third_party/WebKit/Source/build/scripts/templates/MakeQualifiedNames.cpp.tmpl b/third_party/WebKit/Source/build/scripts/templates/MakeQualifiedNames.cpp.tmpl index 36b0b181..781fe0b 100644 --- a/third_party/WebKit/Source/build/scripts/templates/MakeQualifiedNames.cpp.tmpl +++ b/third_party/WebKit/Source/build/scripts/templates/MakeQualifiedNames.cpp.tmpl
@@ -97,9 +97,9 @@ attr_i++; } {% if tags %} - ASSERT(tag_i == {{namespace}}TagsCount); + DCHECK_EQ(tag_i, {{namespace}}TagsCount); {% endif %} - ASSERT(attr_i == {{namespace}}AttrsCount); + DCHECK_EQ(attr_i, {{namespace}}AttrsCount); } } // {{namespace}}
diff --git a/third_party/WebKit/Source/core/animation/LegacyStyleInterpolation.cpp b/third_party/WebKit/Source/core/animation/LegacyStyleInterpolation.cpp index a9b4b53..1190f7d 100644 --- a/third_party/WebKit/Source/core/animation/LegacyStyleInterpolation.cpp +++ b/third_party/WebKit/Source/core/animation/LegacyStyleInterpolation.cpp
@@ -48,7 +48,7 @@ cached_fraction_(0), cached_iteration_(0), cached_value_(start_ ? start_->Clone() : nullptr) { - RELEASE_ASSERT(TypesMatch(start_.get(), end_.get())); + CHECK(TypesMatch(start_.get(), end_.get())); } void LegacyStyleInterpolation::Apply(StyleResolverState& state) const {
diff --git a/third_party/WebKit/Source/core/clipboard/DataObject.cpp b/third_party/WebKit/Source/core/clipboard/DataObject.cpp index e21fadf..480e775 100644 --- a/third_party/WebKit/Source/core/clipboard/DataObject.cpp +++ b/third_party/WebKit/Source/core/clipboard/DataObject.cpp
@@ -248,7 +248,7 @@ } bool DataObject::InternalAddStringItem(DataObjectItem* item) { - ASSERT(item->Kind() == DataObjectItem::kStringKind); + DCHECK_EQ(item->Kind(), DataObjectItem::kStringKind); for (size_t i = 0; i < item_list_.size(); ++i) { if (item_list_[i]->Kind() == DataObjectItem::kStringKind && item_list_[i]->GetType() == item->GetType()) @@ -260,7 +260,7 @@ } void DataObject::InternalAddFileItem(DataObjectItem* item) { - ASSERT(item->Kind() == DataObjectItem::kFileKind); + DCHECK_EQ(item->Kind(), DataObjectItem::kFileKind); item_list_.push_back(item); }
diff --git a/third_party/WebKit/Source/core/clipboard/DataObjectItem.cpp b/third_party/WebKit/Source/core/clipboard/DataObjectItem.cpp index 785d4a52..25a6b89 100644 --- a/third_party/WebKit/Source/core/clipboard/DataObjectItem.cpp +++ b/third_party/WebKit/Source/core/clipboard/DataObjectItem.cpp
@@ -125,7 +125,7 @@ return nullptr; } - ASSERT(source_ == kPasteboardSource); + DCHECK_EQ(source_, kPasteboardSource); if (GetType() == kMimeTypeImagePng) { WebBlobInfo blob_info = Platform::Current()->Clipboard()->ReadImage( WebClipboard::kBufferStandard); @@ -141,12 +141,12 @@ } String DataObjectItem::GetAsString() const { - ASSERT(kind_ == kStringKind); + DCHECK_EQ(kind_, kStringKind); if (source_ == kInternalSource) return data_; - ASSERT(source_ == kPasteboardSource); + DCHECK_EQ(source_, kPasteboardSource); WebClipboard::Buffer buffer = Pasteboard::GeneralPasteboard()->GetBuffer(); String data;
diff --git a/third_party/WebKit/Source/core/dom/ScriptLoader.cpp b/third_party/WebKit/Source/core/dom/ScriptLoader.cpp index 198e1967..539e130 100644 --- a/third_party/WebKit/Source/core/dom/ScriptLoader.cpp +++ b/third_party/WebKit/Source/core/dom/ScriptLoader.cpp
@@ -964,8 +964,8 @@ // "If the script element has an event attribute and a for attribute, and // the script's type is "classic", then run these substeps:" - // TODO(hiroshige): Check the script's type. - if (event_attribute.IsNull() || for_attribute.IsNull()) + if (GetScriptType() != ScriptType::kClassic || event_attribute.IsNull() || + for_attribute.IsNull()) return true; // 3. "Strip leading and trailing ASCII whitespace from event and for."
diff --git a/third_party/WebKit/Source/core/frame/DOMTimerCoordinator.cpp b/third_party/WebKit/Source/core/frame/DOMTimerCoordinator.cpp index 084583e..59b3511 100644 --- a/third_party/WebKit/Source/core/frame/DOMTimerCoordinator.cpp +++ b/third_party/WebKit/Source/core/frame/DOMTimerCoordinator.cpp
@@ -22,7 +22,7 @@ int timeout, bool single_shot) { // FIXME: DOMTimers depends heavily on ExecutionContext. Decouple them. - ASSERT(context->Timers() == this); + DCHECK_EQ(context->Timers(), this); int timeout_id = NextID(); timers_.insert(timeout_id, DOMTimer::Create(context, action, timeout, single_shot, timeout_id));
diff --git a/third_party/WebKit/Source/core/frame/DeprecatedScheduleStyleRecalcDuringLayout.cpp b/third_party/WebKit/Source/core/frame/DeprecatedScheduleStyleRecalcDuringLayout.cpp index ca07acf6..ef2ae2f 100644 --- a/third_party/WebKit/Source/core/frame/DeprecatedScheduleStyleRecalcDuringLayout.cpp +++ b/third_party/WebKit/Source/core/frame/DeprecatedScheduleStyleRecalcDuringLayout.cpp
@@ -22,7 +22,7 @@ // proper state. The style recalc will still have been schedule, however. if (was_in_perform_layout_ && lifecycle_.GetState() != DocumentLifecycle::kInPerformLayout) { - ASSERT(lifecycle_.GetState() == DocumentLifecycle::kVisualUpdatePending); + DCHECK_EQ(lifecycle_.GetState(), DocumentLifecycle::kVisualUpdatePending); lifecycle_.AdvanceTo(DocumentLifecycle::kInPerformLayout); } }
diff --git a/third_party/WebKit/Source/core/frame/FrameView.cpp b/third_party/WebKit/Source/core/frame/FrameView.cpp index 8494a86..0335175 100644 --- a/third_party/WebKit/Source/core/frame/FrameView.cpp +++ b/third_party/WebKit/Source/core/frame/FrameView.cpp
@@ -343,7 +343,7 @@ } void FrameView::Dispose() { - RELEASE_ASSERT(!IsInPerformLayout()); + CHECK(!IsInPerformLayout()); if (ScrollAnimatorBase* scroll_animator = ExistingScrollAnimator()) scroll_animator->CancelAnimation(); @@ -718,7 +718,7 @@ if (layout_view_item.IsNull()) return; - ASSERT(frame_->View() == this); + DCHECK_EQ(frame_->View(), this); const IntRect rect = layout_view_item.DocumentRect(); const IntSize& size = rect.Size(); @@ -815,7 +815,7 @@ void FrameView::RecalcOverflowAfterStyleChange() { LayoutViewItem layout_view_item = this->GetLayoutViewItem(); - RELEASE_ASSERT(!layout_view_item.IsNull()); + CHECK(!layout_view_item.IsNull()); if (!layout_view_item.NeedsOverflowRecalcAfterStyleChange()) return; @@ -1158,7 +1158,7 @@ void FrameView::UpdateLayout() { // We should never layout a Document which is not in a LocalFrame. DCHECK(frame_); - DCHECK(frame_->View() == this); + DCHECK_EQ(frame_->View(), this); DCHECK(frame_->GetPage()); ScriptForbiddenScope forbid_script; @@ -1364,7 +1364,7 @@ Lifecycle().AdvanceTo(DocumentLifecycle::kInPaintInvalidation); - RELEASE_ASSERT(!GetLayoutViewItem().IsNull()); + CHECK(!GetLayoutViewItem().IsNull()); LayoutViewItem root_for_paint_invalidation = GetLayoutViewItem(); DCHECK(!root_for_paint_invalidation.NeedsLayout()); @@ -1384,7 +1384,7 @@ void FrameView::InvalidatePaint( const PaintInvalidationState& paint_invalidation_state) { - RELEASE_ASSERT(!GetLayoutViewItem().IsNull()); + CHECK(!GetLayoutViewItem().IsNull()); if (!RuntimeEnabledFeatures::rootLayerScrollingEnabled()) InvalidatePaintOfScrollControlsIfNeeded(paint_invalidation_state); }
diff --git a/third_party/WebKit/Source/core/frame/LocalDOMWindow.cpp b/third_party/WebKit/Source/core/frame/LocalDOMWindow.cpp index d9996e7..1e6b1b6 100644 --- a/third_party/WebKit/Source/core/frame/LocalDOMWindow.cpp +++ b/third_party/WebKit/Source/core/frame/LocalDOMWindow.cpp
@@ -347,7 +347,7 @@ Document* LocalDOMWindow::InstallNewDocument(const String& mime_type, const DocumentInit& init, bool force_xhtml) { - ASSERT(init.GetFrame() == GetFrame()); + DCHECK_EQ(init.GetFrame(), GetFrame()); ClearDocument();
diff --git a/third_party/WebKit/Source/core/frame/SubresourceIntegrity.cpp b/third_party/WebKit/Source/core/frame/SubresourceIntegrity.cpp index c96242a..78cc9be4 100644 --- a/third_party/WebKit/Source/core/frame/SubresourceIntegrity.cpp +++ b/third_party/WebKit/Source/core/frame/SubresourceIntegrity.cpp
@@ -381,7 +381,7 @@ continue; } - ASSERT(parse_result == kAlgorithmValid); + DCHECK_EQ(parse_result, kAlgorithmValid); if (!ParseDigest(position, current_integrity_end, digest)) { error = true;
diff --git a/third_party/WebKit/Source/core/input/EventHandler.cpp b/third_party/WebKit/Source/core/input/EventHandler.cpp index b370359..6f5bb96 100644 --- a/third_party/WebKit/Source/core/input/EventHandler.cpp +++ b/third_party/WebKit/Source/core/input/EventHandler.cpp
@@ -1071,7 +1071,8 @@ mouse_event_manager_->DispatchDragSrcEvent(EventTypeNames::drag, event); } event_result = mouse_event_manager_->DispatchDragEvent( - EventTypeNames::dragenter, new_target, event, data_transfer); + EventTypeNames::dragenter, new_target, drag_target_, event, + data_transfer); } if (TargetIsFrame(drag_target_.Get(), target_frame)) { @@ -1079,8 +1080,9 @@ event_result = target_frame->GetEventHandler().UpdateDragAndDrop( event, data_transfer); } else if (drag_target_) { - mouse_event_manager_->DispatchDragEvent( - EventTypeNames::dragleave, drag_target_.Get(), event, data_transfer); + mouse_event_manager_->DispatchDragEvent(EventTypeNames::dragleave, + drag_target_.Get(), new_target, + event, data_transfer); } if (new_target) { @@ -1106,7 +1108,7 @@ mouse_event_manager_->DispatchDragSrcEvent(EventTypeNames::drag, event); } event_result = mouse_event_manager_->DispatchDragEvent( - EventTypeNames::dragover, new_target, event, data_transfer); + EventTypeNames::dragover, new_target, nullptr, event, data_transfer); should_only_fire_drag_over_event_ = false; } } @@ -1124,8 +1126,9 @@ } else if (drag_target_.Get()) { if (mouse_event_manager_->GetDragState().drag_src_) mouse_event_manager_->DispatchDragSrcEvent(EventTypeNames::drag, event); - mouse_event_manager_->DispatchDragEvent( - EventTypeNames::dragleave, drag_target_.Get(), event, data_transfer); + mouse_event_manager_->DispatchDragEvent(EventTypeNames::dragleave, + drag_target_.Get(), nullptr, event, + data_transfer); } ClearDragState(); } @@ -1141,7 +1144,8 @@ event, data_transfer); } else if (drag_target_.Get()) { result = mouse_event_manager_->DispatchDragEvent( - EventTypeNames::drop, drag_target_.Get(), event, data_transfer); + EventTypeNames::drop, drag_target_.Get(), nullptr, event, + data_transfer); } ClearDragState(); return result;
diff --git a/third_party/WebKit/Source/core/input/MouseEventManager.cpp b/third_party/WebKit/Source/core/input/MouseEventManager.cpp index 9667803..addf619 100644 --- a/third_party/WebKit/Source/core/input/MouseEventManager.cpp +++ b/third_party/WebKit/Source/core/input/MouseEventManager.cpp
@@ -893,21 +893,28 @@ WebInputEventResult MouseEventManager::DispatchDragSrcEvent( const AtomicString& event_type, const WebMouseEvent& event) { - return DispatchDragEvent(event_type, GetDragState().drag_src_.Get(), event, - GetDragState().drag_data_transfer_.Get()); + return DispatchDragEvent(event_type, GetDragState().drag_src_.Get(), nullptr, + event, GetDragState().drag_data_transfer_.Get()); } WebInputEventResult MouseEventManager::DispatchDragEvent( const AtomicString& event_type, Node* drag_target, + Node* related_target, const WebMouseEvent& event, DataTransfer* data_transfer) { FrameView* view = frame_->View(); - // FIXME: We might want to dispatch a dragleave even if the view is gone. if (!view) return WebInputEventResult::kNotHandled; + // We should be setting relatedTarget correctly following the spec: + // https://html.spec.whatwg.org/multipage/interaction.html#dragevent + // At the same time this should prevent exposing a node from another document. + if (related_target && + related_target->GetDocument() != drag_target->GetDocument()) + related_target = nullptr; + const bool cancelable = event_type != EventTypeNames::dragleave && event_type != EventTypeNames::dragend; @@ -919,7 +926,8 @@ position.Y(), movement.X(), movement.Y(), static_cast<WebInputEvent::Modifiers>(event.GetModifiers()), 0, MouseEvent::WebInputEventModifiersToButtons(event.GetModifiers()), - nullptr, TimeTicks::FromSeconds(event.TimeStampSeconds()), data_transfer, + related_target, TimeTicks::FromSeconds(event.TimeStampSeconds()), + data_transfer, event.FromTouch() ? MouseEvent::kFromTouch : MouseEvent::kRealOrIndistinguishable);
diff --git a/third_party/WebKit/Source/core/input/MouseEventManager.h b/third_party/WebKit/Source/core/input/MouseEventManager.h index 1da27559..16808a6 100644 --- a/third_party/WebKit/Source/core/input/MouseEventManager.h +++ b/third_party/WebKit/Source/core/input/MouseEventManager.h
@@ -64,6 +64,7 @@ const WebMouseEvent&); WebInputEventResult DispatchDragEvent(const AtomicString& event_type, Node* target, + Node* related_target, const WebMouseEvent&, DataTransfer*);
diff --git a/third_party/WebKit/Source/core/inspector/InspectorAnimationAgent.cpp b/third_party/WebKit/Source/core/inspector/InspectorAnimationAgent.cpp index de6c245..95a1ec7 100644 --- a/third_party/WebKit/Source/core/inspector/InspectorAnimationAgent.cpp +++ b/third_party/WebKit/Source/core/inspector/InspectorAnimationAgent.cpp
@@ -387,7 +387,7 @@ // Refer to CSSAnimations::calculateTransitionUpdateForProperty() for the // structure of transitions. const KeyframeVector& frames = old_model->GetFrames(); - ASSERT(frames.size() == 3); + DCHECK(frames.size() == 3); KeyframeVector new_frames; for (int i = 0; i < 3; i++) new_frames.push_back(ToTransitionKeyframe(frames[i]->Clone().Get()));
diff --git a/third_party/WebKit/Source/core/inspector/InspectorCSSAgent.cpp b/third_party/WebKit/Source/core/inspector/InspectorCSSAgent.cpp index e1fea63..e9bfe37f 100644 --- a/third_party/WebKit/Source/core/inspector/InspectorCSSAgent.cpp +++ b/third_party/WebKit/Source/core/inspector/InspectorCSSAgent.cpp
@@ -427,7 +427,7 @@ } void Merge(Action* action) override { - ASSERT(action->MergeId() == MergeId()); + DCHECK_EQ(action->MergeId(), MergeId()); SetStyleSheetTextAction* other = static_cast<SetStyleSheetTextAction*>(action); @@ -548,7 +548,7 @@ bool IsNoop() override { return old_text_ == new_text_; } void Merge(Action* action) override { - ASSERT(action->MergeId() == MergeId()); + DCHECK_EQ(action->MergeId(), MergeId()); ModifyRuleAction* other = static_cast<ModifyRuleAction*>(action); new_text_ = other->new_text_; @@ -605,7 +605,7 @@ } void Merge(Action* action) override { - ASSERT(action->MergeId() == MergeId()); + DCHECK_EQ(action->MergeId(), MergeId()); SetElementStyleAction* other = static_cast<SetElementStyleAction*>(action); text_ = other->text_;
diff --git a/third_party/WebKit/Source/core/inspector/MainThreadDebugger.cpp b/third_party/WebKit/Source/core/inspector/MainThreadDebugger.cpp index 8a7330e..b032703e 100644 --- a/third_party/WebKit/Source/core/inspector/MainThreadDebugger.cpp +++ b/third_party/WebKit/Source/core/inspector/MainThreadDebugger.cpp
@@ -106,7 +106,7 @@ MainThreadDebugger::~MainThreadDebugger() { MutexLocker locker(CreationMutex()); - ASSERT(instance_ == this); + DCHECK_EQ(instance_, this); instance_ = nullptr; } @@ -242,7 +242,7 @@ // Do not pause in Context of detached frame. if (!paused_frame) return; - ASSERT(paused_frame == paused_frame->LocalFrameRoot()); + DCHECK(paused_frame == paused_frame->LocalFrameRoot()); paused_ = true; if (UserGestureToken* token = UserGestureIndicator::CurrentToken())
diff --git a/third_party/WebKit/Source/core/layout/LayoutMenuList.cpp b/third_party/WebKit/Source/core/layout/LayoutMenuList.cpp index 1e210c4..6fc7eaf 100644 --- a/third_party/WebKit/Source/core/layout/LayoutMenuList.cpp +++ b/third_party/WebKit/Source/core/layout/LayoutMenuList.cpp
@@ -125,6 +125,10 @@ inner_style.SetDirection(option_style_->Direction()); inner_style.SetUnicodeBidi(option_style_->GetUnicodeBidi()); } + + // LayoutMenuList::ControlClipRect() depends on inner_block_->ContentsSize(). + if (RuntimeEnabledFeatures::slimmingPaintInvalidationEnabled()) + SetNeedsPaintPropertyUpdate(); } HTMLSelectElement* LayoutMenuList::SelectElement() const { @@ -138,6 +142,10 @@ if (AXObjectCache* cache = GetDocument().ExistingAXObjectCache()) cache->ChildrenChanged(this); + + // LayoutMenuList::ControlClipRect() depends on inner_block_->ContentsSize(). + if (RuntimeEnabledFeatures::slimmingPaintInvalidationEnabled()) + SetNeedsPaintPropertyUpdate(); } void LayoutMenuList::RemoveChild(LayoutObject* old_child) {
diff --git a/third_party/WebKit/Source/core/loader/HistoryItem.cpp b/third_party/WebKit/Source/core/loader/HistoryItem.cpp index 3756e2c5..1c0ff7f 100644 --- a/third_party/WebKit/Source/core/loader/HistoryItem.cpp +++ b/third_party/WebKit/Source/core/loader/HistoryItem.cpp
@@ -72,7 +72,7 @@ } void HistoryItem::SetReferrer(const Referrer& referrer) { - // This should be a RELEASE_ASSERT. + // This should be a CHECK. referrer_ = SecurityPolicy::GenerateReferrer(referrer.referrer_policy, Url(), referrer.referrer); }
diff --git a/third_party/WebKit/Source/core/paint/PaintPropertyTreeBuilder.cpp b/third_party/WebKit/Source/core/paint/PaintPropertyTreeBuilder.cpp index 42d0cb93..3875ba6f5 100644 --- a/third_party/WebKit/Source/core/paint/PaintPropertyTreeBuilder.cpp +++ b/third_party/WebKit/Source/core/paint/PaintPropertyTreeBuilder.cpp
@@ -791,7 +791,7 @@ } } -static bool NeedsOverflowScroll(const LayoutObject& object) { +static bool NeedsOverflowClip(const LayoutObject& object) { return object.IsBox() && ToLayoutBox(object).ShouldClipOverflow(); } @@ -800,7 +800,7 @@ PaintPropertyTreeBuilderFragmentContext& context, bool& force_subtree_update) { if (object.NeedsPaintPropertyUpdate() || force_subtree_update) { - if (NeedsOverflowScroll(object)) { + if (NeedsOverflowClip(object)) { const LayoutBox& box = ToLayoutBox(object); LayoutRect clip_rect; clip_rect = @@ -1186,7 +1186,7 @@ NeedsPaintOffsetTranslation(object) || NeedsTransform(object) || NeedsEffect(object) || NeedsTransformForNonRootSVG(object) || NeedsFilter(object) || NeedsCssClip(object) || - NeedsScrollbarPaintOffset(object) || NeedsOverflowScroll(object) || + NeedsScrollbarPaintOffset(object) || NeedsOverflowClip(object) || NeedsPerspective(object) || NeedsSVGLocalToBorderBoxTransform(object) || NeedsScrollTranslation(object) || NeedsCssClipFixedPosition(object);
diff --git a/third_party/WebKit/Source/core/paint/PaintPropertyTreeUpdateTests.cpp b/third_party/WebKit/Source/core/paint/PaintPropertyTreeUpdateTests.cpp index 4269939..71f01e5 100644 --- a/third_party/WebKit/Source/core/paint/PaintPropertyTreeUpdateTests.cpp +++ b/third_party/WebKit/Source/core/paint/PaintPropertyTreeUpdateTests.cpp
@@ -3,6 +3,7 @@ // found in the LICENSE file. #include "core/html/HTMLIFrameElement.h" +#include "core/html/HTMLSelectElement.h" #include "core/paint/PaintPropertyTreeBuilderTest.h" #include "core/paint/PaintPropertyTreePrinter.h" @@ -752,4 +753,20 @@ EXPECT_FALSE(transform->FlattensInheritedTransform()); } +TEST_P(PaintPropertyTreeUpdateTest, MenuListControlClipChange) { + SetBodyInnerHTML( + "<select id='select' style='white-space: normal'>" + " <option></option>" + " <option>bar</option>" + "</select>"); + + auto* select = GetLayoutObjectByElementId("select"); + EXPECT_NE(nullptr, select->PaintProperties()->OverflowClip()); + + // Should not assert in FindPropertiesNeedingUpdate. + toHTMLSelectElement(select->GetNode())->setSelectedIndex(1); + GetDocument().View()->UpdateAllLifecyclePhases(); + EXPECT_NE(nullptr, select->PaintProperties()->OverflowClip()); +} + } // namespace blink
diff --git a/third_party/WebKit/Source/core/paint/PrePaintTreeWalk.cpp b/third_party/WebKit/Source/core/paint/PrePaintTreeWalk.cpp index 346651b..0e4e472d 100644 --- a/third_party/WebKit/Source/core/paint/PrePaintTreeWalk.cpp +++ b/third_party/WebKit/Source/core/paint/PrePaintTreeWalk.cpp
@@ -309,7 +309,6 @@ UpdateAuxiliaryObjectProperties(object, context); if (context.tree_builder_context) { - DCHECK(context.tree_builder_context); property_tree_builder_.UpdatePropertiesForSelf( object, *context.tree_builder_context); }
diff --git a/third_party/WebKit/Source/core/workers/WorkerThread.h b/third_party/WebKit/Source/core/workers/WorkerThread.h index d8da5e4a..1519bb69 100644 --- a/third_party/WebKit/Source/core/workers/WorkerThread.h +++ b/third_party/WebKit/Source/core/workers/WorkerThread.h
@@ -129,7 +129,7 @@ bool IsCurrentThread(); WorkerLoaderProxy* GetWorkerLoaderProxy() const { - RELEASE_ASSERT(worker_loader_proxy_); + CHECK(worker_loader_proxy_); return worker_loader_proxy_.Get(); }
diff --git a/third_party/WebKit/Source/devtools/front_end/timeline/TimelineTreeView.js b/third_party/WebKit/Source/devtools/front_end/timeline/TimelineTreeView.js index ed97566..484b1d1 100644 --- a/third_party/WebKit/Source/devtools/front_end/timeline/TimelineTreeView.js +++ b/third_party/WebKit/Source/devtools/front_end/timeline/TimelineTreeView.js
@@ -863,7 +863,7 @@ */ _productByEvent(event) { var url = TimelineModel.TimelineProfileTree.eventURL(event); - if (!url) + if (!url || !this._productByURLCache) return ''; if (this._productByURLCache.has(url)) return this._productByURLCache.get(url);
diff --git a/third_party/WebKit/Source/modules/canvas2d/CanvasRenderingContext2D.cpp b/third_party/WebKit/Source/modules/canvas2d/CanvasRenderingContext2D.cpp index cc2d4d1..0f4f547 100644 --- a/third_party/WebKit/Source/modules/canvas2d/CanvasRenderingContext2D.cpp +++ b/third_party/WebKit/Source/modules/canvas2d/CanvasRenderingContext2D.cpp
@@ -853,7 +853,7 @@ // anti-aliasing, which is expected when !creationAttributes().alpha(), so we // need to fall out of display list mode when drawing text to an opaque // canvas. crbug.com/583809 - if (!CreationAttributes().alpha() && !IsComposited()) { + if (!IsComposited()) { canvas()->DisableDeferral( kDisableDeferralReasonSubPixelTextAntiAliasingSupport); }
diff --git a/third_party/WebKit/Source/modules/canvas2d/CanvasRenderingContext2DTest.cpp b/third_party/WebKit/Source/modules/canvas2d/CanvasRenderingContext2DTest.cpp index 364aac9..5d1cad91 100644 --- a/third_party/WebKit/Source/modules/canvas2d/CanvasRenderingContext2DTest.cpp +++ b/third_party/WebKit/Source/modules/canvas2d/CanvasRenderingContext2DTest.cpp
@@ -832,19 +832,6 @@ EXPECT_FALSE(surface_ptr->IsRecording()); } -TEST_F(CanvasRenderingContext2DTest, - NonOpaqueDisplayListDoesNotFallBackForText) { - CreateContext(kNonOpaque); - auto surface = WTF::MakeUnique<RecordingImageBufferSurface>( - IntSize(10, 10), RecordingImageBufferSurface::kAllowFallback, kNonOpaque); - auto* surface_ptr = surface.get(); - CanvasElement().CreateImageBufferUsingSurfaceForTesting(std::move(surface)); - - Context2d()->fillText("Text", 0, 5); - - EXPECT_TRUE(surface_ptr->IsRecording()); -} - TEST_F(CanvasRenderingContext2DTest, ImageResourceLifetime) { NonThrowableExceptionState non_throwable_exception_state; Element* canvas_element =
diff --git a/third_party/WebKit/Source/modules/webaudio/AudioParam.cpp b/third_party/WebKit/Source/modules/webaudio/AudioParam.cpp index c133ea7..4b89864 100644 --- a/third_party/WebKit/Source/modules/webaudio/AudioParam.cpp +++ b/third_party/WebKit/Source/modules/webaudio/AudioParam.cpp
@@ -51,7 +51,7 @@ max_value_(max_value) { // The destination MUST exist because we need the destination handler for the // AudioParam. - RELEASE_ASSERT(context.destination()); + CHECK(context.destination()); destination_handler_ = &context.destination()->GetAudioDestinationHandler(); timeline_.SetSmoothedValue(default_value);
diff --git a/third_party/WebKit/Source/modules/webaudio/IIRFilterNode.cpp b/third_party/WebKit/Source/modules/webaudio/IIRFilterNode.cpp index 42adea1..f8a525d 100644 --- a/third_party/WebKit/Source/modules/webaudio/IIRFilterNode.cpp +++ b/third_party/WebKit/Source/modules/webaudio/IIRFilterNode.cpp
@@ -7,6 +7,7 @@ #include "bindings/core/v8/ExceptionMessages.h" #include "bindings/core/v8/ExceptionState.h" #include "core/dom/ExceptionCode.h" +#include "core/inspector/ConsoleMessage.h" #include "modules/webaudio/AudioBasicProcessorHandler.h" #include "modules/webaudio/BaseAudioContext.h" #include "modules/webaudio/IIRFilterOptions.h" @@ -15,6 +16,51 @@ namespace blink { +// Determine if filter is stable based on the feedback coefficients. +// We compute the reflection coefficients for the filter. If, at any +// point, the magnitude of the reflection coefficient is greater than +// or equal to 1, the filter is declared unstable. +// +// Let A(z) be the feedback polynomial given by +// A[n](z) = 1 + a[1]/z + a[2]/z^2 + ... + a[n]/z^n +// +// The first reflection coefficient k[n] = a[n]. Then, recursively compute +// +// A[n-1](z) = (A[n](z) - k[n]*A[n](1/z)/z^n)/(1-k[n]^2); +// +// stopping at A[1](z). If at any point |k[n]| >= 1, the filter is +// unstable. +static bool IsFilterStable(const Vector<double>& feedback_coef) { + // Make a copy of the feedback coefficients + Vector<double> coef(feedback_coef); + int order = coef.size() - 1; + + // If necessary, normalize filter coefficients so that constant term is 1. + if (coef[0] != 1) { + for (int m = 1; m <= order; ++m) + coef[m] /= coef[0]; + coef[0] = 1; + } + + // Begin recursion, using a work array to hold intermediate results. + Vector<double> work(order + 1); + for (int n = order; n >= 1; --n) { + double k = coef[n]; + + if (std::fabs(k) >= 1) + return false; + + // Note that A[n](1/z)/z^n is basically the coefficients of A[n] + // in reverse order. + double factor = 1 - k * k; + for (int m = 0; m <= n; ++m) + work[m] = (coef[m] - k * coef[n - m]) / factor; + coef.swap(work); + } + + return true; +} + IIRFilterNode::IIRFilterNode(BaseAudioContext& context, const Vector<double>& feedforward_coef, const Vector<double>& feedback_coef) @@ -88,6 +134,20 @@ return nullptr; } + if (!IsFilterStable(feedback_coef)) { + StringBuilder message; + message.Append("Unstable IIRFilter with feedback coefficients: ["); + message.AppendNumber(feedback_coef[0]); + for (size_t k = 1; k < feedback_coef.size(); ++k) { + message.Append(", "); + message.AppendNumber(feedback_coef[k]); + } + message.Append(']'); + + context.GetExecutionContext()->AddConsoleMessage(ConsoleMessage::Create( + kJSMessageSource, kWarningMessageLevel, message.ToString())); + } + return new IIRFilterNode(context, feedforward_coef, feedback_coef); }
diff --git a/third_party/WebKit/Source/modules/webaudio/PannerNode.cpp b/third_party/WebKit/Source/modules/webaudio/PannerNode.cpp index 58be8223..94a4364 100644 --- a/third_party/WebKit/Source/modules/webaudio/PannerNode.cpp +++ b/third_party/WebKit/Source/modules/webaudio/PannerNode.cpp
@@ -166,7 +166,7 @@ void PannerHandler::ProcessSampleAccurateValues(AudioBus* destination, const AudioBus* source, size_t frames_to_process) { - RELEASE_ASSERT(frames_to_process <= AudioUtilities::kRenderQuantumFrames); + CHECK_LE(frames_to_process, AudioUtilities::kRenderQuantumFrames); // Get the sample accurate values from all of the AudioParams, including the // values from the AudioListener.
diff --git a/third_party/WebKit/Source/modules/webdatabase/sqlite/SQLiteDatabase.cpp b/third_party/WebKit/Source/modules/webdatabase/sqlite/SQLiteDatabase.cpp index 8dd5d0d..ae92d3e 100644 --- a/third_party/WebKit/Source/modules/webdatabase/sqlite/SQLiteDatabase.cpp +++ b/third_party/WebKit/Source/modules/webdatabase/sqlite/SQLiteDatabase.cpp
@@ -101,7 +101,7 @@ if (db_) { // FIXME: This is being called on the main thread during JS GC. // <rdar://problem/5739818> - // ASSERT(currentThread() == m_openingThread); + // DCHECK_EQ(currentThread(), m_openingThread); sqlite3* db = db_; { MutexLocker locker(database_closing_mutex_);
diff --git a/third_party/WebKit/Source/platform/LifecycleNotifier.h b/third_party/WebKit/Source/platform/LifecycleNotifier.h index 56ea1799..16e04d3d 100644 --- a/third_party/WebKit/Source/platform/LifecycleNotifier.h +++ b/third_party/WebKit/Source/platform/LifecycleNotifier.h
@@ -144,7 +144,7 @@ template <typename T, typename Observer> inline void LifecycleNotifier<T, Observer>::AddObserver(Observer* observer) { - RELEASE_ASSERT(iteration_state_ & kAllowingAddition); + CHECK(iteration_state_ & kAllowingAddition); observers_.insert(observer); } @@ -156,7 +156,7 @@ observers_.insert(observer); return; } - RELEASE_ASSERT(iteration_state_ & kAllowingRemoval); + CHECK(iteration_state_ & kAllowingRemoval); observers_.erase(observer); }
diff --git a/third_party/WebKit/Source/platform/image-decoders/FastSharedBufferReader.cpp b/third_party/WebKit/Source/platform/image-decoders/FastSharedBufferReader.cpp index eb2f4f9..7d7ce91 100644 --- a/third_party/WebKit/Source/platform/image-decoders/FastSharedBufferReader.cpp +++ b/third_party/WebKit/Source/platform/image-decoders/FastSharedBufferReader.cpp
@@ -54,7 +54,7 @@ const char* FastSharedBufferReader::GetConsecutiveData(size_t data_position, size_t length, char* buffer) const { - RELEASE_ASSERT(data_position + length <= data_->size()); + CHECK_LE(data_position + length, data_->size()); // Use the cached segment if it can serve the request. if (data_position >= data_position_ &&
diff --git a/third_party/WebKit/Source/platform/image-decoders/gif/GIFImageReader.cpp b/third_party/WebKit/Source/platform/image-decoders/gif/GIFImageReader.cpp index 38cf46e..0d5b949 100644 --- a/third_party/WebKit/Source/platform/image-decoders/gif/GIFImageReader.cpp +++ b/third_party/WebKit/Source/platform/image-decoders/gif/GIFImageReader.cpp
@@ -310,8 +310,7 @@ if (!m_isDefined || !m_table.IsEmpty()) return; - RELEASE_ASSERT(m_position + m_colors * BYTES_PER_COLORMAP_ENTRY <= - reader->size()); + CHECK_LE(m_position + m_colors * BYTES_PER_COLORMAP_ENTRY, reader->size()); DCHECK_LE(m_colors, MAX_COLORS); char buffer[MAX_COLORS * BYTES_PER_COLORMAP_ENTRY]; const unsigned char* srcColormap =
diff --git a/third_party/WebKit/Source/platform/mhtml/MHTMLParser.cpp b/third_party/WebKit/Source/platform/mhtml/MHTMLParser.cpp index a4ca390..691d3df 100644 --- a/third_party/WebKit/Source/platform/mhtml/MHTMLParser.cpp +++ b/third_party/WebKit/Source/platform/mhtml/MHTMLParser.cpp
@@ -303,7 +303,7 @@ return nullptr; } end_of_part_reached = true; - DCHECK_EQ(next_chars.size(), 2UL); + DCHECK(next_chars.size() == 2); end_of_archive_reached = (next_chars[0] == '-' && next_chars[1] == '-'); if (!end_of_archive_reached) { String line = line_reader_.NextChunkAsUTF8StringWithLatin1Fallback();
diff --git a/third_party/WebKit/Source/platform/scheduler/base/queueing_time_estimator.cc b/third_party/WebKit/Source/platform/scheduler/base/queueing_time_estimator.cc index 526122d..b3b43cc 100644 --- a/third_party/WebKit/Source/platform/scheduler/base/queueing_time_estimator.cc +++ b/third_party/WebKit/Source/platform/scheduler/base/queueing_time_estimator.cc
@@ -59,9 +59,12 @@ QueueingTimeEstimator::QueueingTimeEstimator( QueueingTimeEstimator::Client* client, - base::TimeDelta window_duration) - : client_(client) { + base::TimeDelta window_duration, + int steps_per_window) + : client_(client), state_(steps_per_window) { + DCHECK(steps_per_window >= 1); state_.window_duration = window_duration; + state_.window_step_width = window_duration / steps_per_window; } QueueingTimeEstimator::QueueingTimeEstimator(const State& state) @@ -81,6 +84,9 @@ state_.OnBeginNestedRunLoop(); } +QueueingTimeEstimator::State::State(int steps_per_window) + : step_queueing_times(steps_per_window) {} + void QueueingTimeEstimator::State::OnTopLevelTaskStarted( base::TimeTicks task_start_time) { current_task_start_time = task_start_time; @@ -94,10 +100,8 @@ current_task_start_time = base::TimeTicks(); return; } - if (window_start_time.is_null()) window_start_time = current_task_start_time; - if (task_end_time - current_task_start_time > kInvalidTaskThreshold) { // This task took too long, so we'll pretend it never happened. This could // be because the user's machine went to sleep during a task. @@ -108,18 +112,20 @@ while (TimePastWindowEnd(task_end_time)) { if (!TimePastWindowEnd(current_task_start_time)) { // Include the current task in this window. - current_expected_queueing_time += ExpectedQueueingTimeFromTask( + step_expected_queueing_time += ExpectedQueueingTimeFromTask( current_task_start_time, task_end_time, window_start_time, - window_start_time + window_duration); + window_start_time + window_step_width); } - client->OnQueueingTimeForWindowEstimated(current_expected_queueing_time); - window_start_time += window_duration; - current_expected_queueing_time = base::TimeDelta(); + step_queueing_times.Add(step_expected_queueing_time); + client->OnQueueingTimeForWindowEstimated(step_queueing_times.GetAverage(), + window_start_time); + window_start_time += window_step_width; + step_expected_queueing_time = base::TimeDelta(); } - current_expected_queueing_time += ExpectedQueueingTimeFromTask( + step_expected_queueing_time += ExpectedQueueingTimeFromTask( current_task_start_time, task_end_time, window_start_time, - window_start_time + window_duration); + window_start_time + window_step_width); current_task_start_time = base::TimeTicks(); } @@ -129,7 +135,27 @@ } bool QueueingTimeEstimator::State::TimePastWindowEnd(base::TimeTicks time) { - return time > window_start_time + window_duration; + return time > window_start_time + window_step_width; +} + +QueueingTimeEstimator::RunningAverage::RunningAverage(int size) { + circular_buffer_.resize(size); + index_ = 0; +} + +int QueueingTimeEstimator::RunningAverage::GetStepsPerWindow() const { + return circular_buffer_.size(); +} + +void QueueingTimeEstimator::RunningAverage::Add(base::TimeDelta bin_value) { + running_sum_ -= circular_buffer_[index_]; + circular_buffer_[index_] = bin_value; + running_sum_ += bin_value; + index_ = (index_ + 1) % circular_buffer_.size(); +} + +base::TimeDelta QueueingTimeEstimator::RunningAverage::GetAverage() const { + return running_sum_ / circular_buffer_.size(); } // Keeps track of the queueing time. @@ -137,7 +163,8 @@ public: // QueueingTimeEstimator::Client implementation: void OnQueueingTimeForWindowEstimated( - base::TimeDelta queueing_time) override { + base::TimeDelta queueing_time, + base::TimeTicks window_start_time) override { queueing_time_ = queueing_time; } @@ -167,11 +194,26 @@ temporary_queueing_time_estimator_state.OnTopLevelTaskCompleted( &record_queueing_time_client, now); - // Report the max of the queueing time for the last full window, or the - // current partial window. - return std::max( - record_queueing_time_client.queueing_time(), - temporary_queueing_time_estimator_state.current_expected_queueing_time); + // Report the max of the queueing time for the last window, or the on-going + // window (tmp window in chart) which includes the current task. + // + // Estimate + // | + // v + // Actual Task |-------------------------... + // Assumed Task |----------------| + // Time |---o---o---o---o---o---o--------> + // 0 1 2 3 4 5 6 + // | s | s | s | s | s | s | + // |----last window----| + // |----tmp window-----| + RunningAverage& temporary_step_queueing_times = + temporary_queueing_time_estimator_state.step_queueing_times; + temporary_step_queueing_times.Add( + temporary_queueing_time_estimator_state.step_expected_queueing_time); + + return std::max(record_queueing_time_client.queueing_time(), + temporary_step_queueing_times.GetAverage()); } } // namespace scheduler
diff --git a/third_party/WebKit/Source/platform/scheduler/base/queueing_time_estimator.h b/third_party/WebKit/Source/platform/scheduler/base/queueing_time_estimator.h index aea0e6b..e548cb9 100644 --- a/third_party/WebKit/Source/platform/scheduler/base/queueing_time_estimator.h +++ b/third_party/WebKit/Source/platform/scheduler/base/queueing_time_estimator.h
@@ -9,6 +9,8 @@ #include "base/time/time.h" #include "platform/PlatformExport.h" +#include <vector> + namespace blink { namespace scheduler { @@ -19,7 +21,8 @@ class PLATFORM_EXPORT Client { public: virtual void OnQueueingTimeForWindowEstimated( - base::TimeDelta queueing_time) = 0; + base::TimeDelta queueing_time, + base::TimeTicks window_start_time) = 0; Client() {} virtual ~Client() {} @@ -27,23 +30,71 @@ DISALLOW_COPY_AND_ASSIGN(Client); }; + class RunningAverage { + public: + explicit RunningAverage(int steps_per_window); + int GetStepsPerWindow() const; + void Add(base::TimeDelta bin_value); + base::TimeDelta GetAverage() const; + + private: + int index_; + std::vector<base::TimeDelta> circular_buffer_; + base::TimeDelta running_sum_; + }; + class State { public: + explicit State(int steps_per_window); void OnTopLevelTaskStarted(base::TimeTicks task_start_time); void OnTopLevelTaskCompleted(Client* client, base::TimeTicks task_end_time); void OnBeginNestedRunLoop(); - base::TimeDelta current_expected_queueing_time; + // |step_expected_queueing_time| is the expected queuing time of a + // smaller window of a step's width. By combining these step EQTs through a + // running average, we can get window EQTs of a bigger window. + // + // ^ Instantaneous queuing time + // | + // | + // | |\ . + // | | \ |\ |\ . + // | | \ | \ |\ | \ . + // | | \ |\ | \ | \ | \ . + // | | \ | \ | \ | \ | \ . + // ------------------------------------------------> Time + // + // |stepEQT|stepEQT|stepEQT|stepEQT|stepEQT|stepEQT| + // + // |------windowEQT_1------| + // |------windowEQT_2------| + // |------windowEQT_3------| + // + // In this case: + // |steps_per_window| = 3, because each window is the length of 3 steps. + + base::TimeDelta step_expected_queueing_time; + // |window_duration| is the size of the sliding window. base::TimeDelta window_duration; + base::TimeDelta window_step_width; + // |steps_per_window| is the ratio of |window_duration| to the sliding + // window's step width. It is an integer since the window must be a integer + // multiple of the step's width. This parameter is used for deciding the + // sliding window's step width, and the number of bins of the circular + // buffer. + int steps_per_window; base::TimeTicks window_start_time; base::TimeTicks current_task_start_time; + RunningAverage step_queueing_times; private: bool TimePastWindowEnd(base::TimeTicks task_end_time); bool in_nested_message_loop_ = false; }; - QueueingTimeEstimator(Client* client, base::TimeDelta window_duration); + QueueingTimeEstimator(Client* client, + base::TimeDelta window_duration, + int steps_per_window); explicit QueueingTimeEstimator(const State& state); void OnTopLevelTaskStarted(base::TimeTicks task_start_time);
diff --git a/third_party/WebKit/Source/platform/scheduler/base/queueing_time_estimator_unittest.cc b/third_party/WebKit/Source/platform/scheduler/base/queueing_time_estimator_unittest.cc index f1526c6d..1a5fa904 100644 --- a/third_party/WebKit/Source/platform/scheduler/base/queueing_time_estimator_unittest.cc +++ b/third_party/WebKit/Source/platform/scheduler/base/queueing_time_estimator_unittest.cc
@@ -3,6 +3,7 @@ // found in the LICENSE file. #include "platform/scheduler/base/queueing_time_estimator.h" +#include "base/logging.h" #include "platform/scheduler/base/test_time_source.h" #include "testing/gmock/include/gmock/gmock.h" #include "testing/gtest/include/gtest/gtest.h" @@ -15,7 +16,8 @@ class TestQueueingTimeEstimatorClient : public QueueingTimeEstimator::Client { public: void OnQueueingTimeForWindowEstimated( - base::TimeDelta queueing_time) override { + base::TimeDelta queueing_time, + base::TimeTicks window_start_time) override { expected_queueing_times_.push_back(queueing_time); } const std::vector<base::TimeDelta>& expected_queueing_times() { @@ -29,8 +31,9 @@ class QueueingTimeEstimatorForTest : public QueueingTimeEstimator { public: QueueingTimeEstimatorForTest(TestQueueingTimeEstimatorClient* client, - base::TimeDelta window_duration) - : QueueingTimeEstimator(client, window_duration) {} + base::TimeDelta window_duration, + int steps_per_window) + : QueueingTimeEstimator(client, window_duration, steps_per_window) {} }; // Three tasks of one second each, all within a 5 second window. Expected @@ -41,7 +44,7 @@ base::TimeTicks time; TestQueueingTimeEstimatorClient client; QueueingTimeEstimatorForTest estimator(&client, - base::TimeDelta::FromSeconds(5)); + base::TimeDelta::FromSeconds(5), 1); for (int i = 0; i < 3; ++i) { estimator.OnTopLevelTaskStarted(time); time += base::TimeDelta::FromMilliseconds(1000); @@ -68,7 +71,7 @@ TEST_F(QueueingTimeEstimatorTest, MultiWindowTask) { TestQueueingTimeEstimatorClient client; QueueingTimeEstimatorForTest estimator(&client, - base::TimeDelta::FromSeconds(5)); + base::TimeDelta::FromSeconds(5), 1); base::TimeTicks time; time += base::TimeDelta::FromMilliseconds(5000); estimator.OnTopLevelTaskStarted(time); @@ -103,7 +106,7 @@ EstimateQueueingTimeDuringSingleLongTaskIncompleteWindow) { TestQueueingTimeEstimatorClient client; QueueingTimeEstimatorForTest estimator(&client, - base::TimeDelta::FromSeconds(5)); + base::TimeDelta::FromSeconds(5), 1); base::TimeTicks time; time += base::TimeDelta::FromMilliseconds(5000); estimator.OnTopLevelTaskStarted(time); @@ -128,7 +131,7 @@ EstimateQueueingTimeDuringSingleLongTaskExceedingWindow) { TestQueueingTimeEstimatorClient client; QueueingTimeEstimatorForTest estimator(&client, - base::TimeDelta::FromSeconds(5)); + base::TimeDelta::FromSeconds(5), 1); base::TimeTicks time; time += base::TimeDelta::FromMilliseconds(5000); estimator.OnTopLevelTaskStarted(time); @@ -144,13 +147,87 @@ EXPECT_EQ(base::TimeDelta::FromMilliseconds(5500), estimated_queueing_time); } +// Estimate +// | +// v +// Task|------------------------------... +// Time|---o---o---o---o---o---o--------> +// 0 1 2 3 4 5 6 +// | s | s | s | s | s | +// |--------win1-------| +// |--------win2-------| +// +// s: step window +// win1: The last full window. +// win2: The partial window. +// +// EQT(win1) = (0.5 + 5.5) / 2 * (5 / 5) = 3 +// EQT(win2) = (4.5 + 0) / 2 * (4.5 / 5) = 2.025 +// So EQT = max(EQT(win1), EQT(win2)) = 3 +TEST_F(QueueingTimeEstimatorTest, + SlidingWindowEstimateQueueingTimeFullWindowLargerThanPartial) { + TestQueueingTimeEstimatorClient client; + QueueingTimeEstimatorForTest estimator(&client, + base::TimeDelta::FromSeconds(5), 5); + base::TimeTicks time; + time += base::TimeDelta::FromMilliseconds(5000); + estimator.OnTopLevelTaskStarted(time); + estimator.OnTopLevelTaskCompleted(time); + + base::TimeTicks start_time = time; + estimator.OnTopLevelTaskStarted(start_time); + + time += base::TimeDelta::FromMilliseconds(5500); + + base::TimeDelta estimated_queueing_time = + estimator.EstimateQueueingTimeIncludingCurrentTask(time); + + EXPECT_EQ(base::TimeDelta::FromMilliseconds(3000), estimated_queueing_time); +} +// Estimate +// | +// v +// Task |----------... +// Time|---o---o---o---o---o---o--------> +// 0 1 2 3 4 5 6 +// | s | s | s | s | s | +// |--------win1-------| +// |--------win2-------| +// +// s: step window +// win1: The last full window. +// win2: The partial window. +// +// EQT(win1) = 0 +// EQT(win2) = (0 + 0.5) / 2 * (0.5 / 2) = 0.025 +// So EQT = max(EQT(win1), EQT(win2)) = 0.025 +TEST_F(QueueingTimeEstimatorTest, + SlidingWindowEstimateQueueingTimePartialWindowLargerThanFull) { + TestQueueingTimeEstimatorClient client; + QueueingTimeEstimatorForTest estimator(&client, + base::TimeDelta::FromSeconds(5), 5); + base::TimeTicks time; + time += base::TimeDelta::FromMilliseconds(5000); + estimator.OnTopLevelTaskStarted(time); + estimator.OnTopLevelTaskCompleted(time); + + time += base::TimeDelta::FromMilliseconds(5000); + base::TimeTicks start_time = time; + estimator.OnTopLevelTaskStarted(start_time); + time += base::TimeDelta::FromMilliseconds(500); + + base::TimeDelta estimated_queueing_time = + estimator.EstimateQueueingTimeIncludingCurrentTask(time); + + EXPECT_EQ(base::TimeDelta::FromMilliseconds(25), estimated_queueing_time); +} // Tasks containing nested run loops may be extremely long without // negatively impacting user experience. Ignore such tasks. TEST_F(QueueingTimeEstimatorTest, IgnoresTasksWithNestedMessageLoops) { TestQueueingTimeEstimatorClient client; QueueingTimeEstimatorForTest estimator(&client, - base::TimeDelta::FromSeconds(5)); + base::TimeDelta::FromSeconds(5), 1); base::TimeTicks time; time += base::TimeDelta::FromMilliseconds(5000); estimator.OnTopLevelTaskStarted(time); @@ -189,7 +266,7 @@ TEST_F(QueueingTimeEstimatorTest, IgnoreExtremelyLongTasks) { TestQueueingTimeEstimatorClient client; QueueingTimeEstimatorForTest estimator(&client, - base::TimeDelta::FromSeconds(5)); + base::TimeDelta::FromSeconds(5), 1); // Start with a 1 second task. base::TimeTicks time; estimator.OnTopLevelTaskStarted(time); @@ -223,5 +300,153 @@ base::TimeDelta::FromMilliseconds(100))); } +// ^ Instantaneous queuing time +// | +// | +// | |\ . +// | | \ . +// | | \ . +// | | \ . +// | | \ | . +// ------------------------------------------------> Time +// |s|s|s|s|s| +// |---win---| +// |---win---| +// |---win---| +TEST_F(QueueingTimeEstimatorTest, SlidingWindowOverOneTask) { + TestQueueingTimeEstimatorClient client; + QueueingTimeEstimatorForTest estimator(&client, + base::TimeDelta::FromSeconds(5), 5); + base::TimeTicks time; + time += base::TimeDelta::FromMilliseconds(1000); + + estimator.OnTopLevelTaskStarted(time); + time += base::TimeDelta::FromMilliseconds(5000); + estimator.OnTopLevelTaskCompleted(time); + + time += base::TimeDelta::FromMilliseconds(6000); + + estimator.OnTopLevelTaskStarted(time); + estimator.OnTopLevelTaskCompleted(time); + + EXPECT_THAT(client.expected_queueing_times(), + testing::ElementsAre(base::TimeDelta::FromMilliseconds(900), + base::TimeDelta::FromMilliseconds(1600), + base::TimeDelta::FromMilliseconds(2100), + base::TimeDelta::FromMilliseconds(2400), + base::TimeDelta::FromMilliseconds(2500), + base::TimeDelta::FromMilliseconds(1600), + base::TimeDelta::FromMilliseconds(900), + base::TimeDelta::FromMilliseconds(400), + base::TimeDelta::FromMilliseconds(100), + base::TimeDelta::FromMilliseconds(0))); +} + +// ^ Instantaneous queuing time +// | +// | +// | |\ . +// | | \ . +// | | \ . +// | | \ |\ . +// | | \ | \ | . +// ------------------------------------------------> Time +// |s|s|s|s|s| +// |---win---| +// |---win---| +// |---win---| +TEST_F(QueueingTimeEstimatorTest, SlidingWindowOverTwoTasksWithinFirstWindow) { + TestQueueingTimeEstimatorClient client; + QueueingTimeEstimatorForTest estimator(&client, + base::TimeDelta::FromSeconds(5), 5); + base::TimeTicks time; + time += base::TimeDelta::FromMilliseconds(1000); + + estimator.OnTopLevelTaskStarted(time); + time += base::TimeDelta::FromMilliseconds(2500); + estimator.OnTopLevelTaskCompleted(time); + + time += base::TimeDelta::FromMilliseconds(500); + + estimator.OnTopLevelTaskStarted(time); + time += base::TimeDelta::FromMilliseconds(1000); + estimator.OnTopLevelTaskCompleted(time); + + time += base::TimeDelta::FromMilliseconds(6000); + + estimator.OnTopLevelTaskStarted(time); + estimator.OnTopLevelTaskCompleted(time); + + std::vector<base::TimeDelta> expected_durations = { + base::TimeDelta::FromMilliseconds(400), + base::TimeDelta::FromMilliseconds(600), + base::TimeDelta::FromMilliseconds(625), + base::TimeDelta::FromMilliseconds(725), + base::TimeDelta::FromMilliseconds(725), + base::TimeDelta::FromMilliseconds(325), + base::TimeDelta::FromMilliseconds(125), + base::TimeDelta::FromMilliseconds(100), + base::TimeDelta::FromMilliseconds(0)}; + EXPECT_THAT(client.expected_queueing_times(), + testing::ElementsAreArray(expected_durations)); +} + +// ^ Instantaneous queuing time +// | +// | +// | |\ . +// | | \ . +// | | \ . +// | | \ |\ . +// | | \| \ | . +// ------------------------------------------------> Time +// |s|s|s|s|s| +// |---win---| +// |---win---| +// |---win---| +TEST_F(QueueingTimeEstimatorTest, + SlidingWindowOverTwoTasksSpanningSeveralWindows) { + TestQueueingTimeEstimatorClient client; + QueueingTimeEstimatorForTest estimator(&client, + base::TimeDelta::FromSeconds(5), 5); + base::TimeTicks time; + time += base::TimeDelta::FromMilliseconds(1000); + estimator.OnTopLevelTaskStarted(time); + estimator.OnTopLevelTaskCompleted(time); + + time += base::TimeDelta::FromMilliseconds(4000); + + estimator.OnTopLevelTaskStarted(time); + time += base::TimeDelta::FromMilliseconds(2500); + estimator.OnTopLevelTaskCompleted(time); + + estimator.OnTopLevelTaskStarted(time); + time += base::TimeDelta::FromMilliseconds(1000); + estimator.OnTopLevelTaskCompleted(time); + + time += base::TimeDelta::FromMilliseconds(6000); + + estimator.OnTopLevelTaskStarted(time); + estimator.OnTopLevelTaskCompleted(time); + + std::vector<base::TimeDelta> expected_durations = { + base::TimeDelta::FromMilliseconds(0), + base::TimeDelta::FromMilliseconds(0), + base::TimeDelta::FromMilliseconds(0), + base::TimeDelta::FromMilliseconds(0), + base::TimeDelta::FromMilliseconds(400), + base::TimeDelta::FromMilliseconds(600), + base::TimeDelta::FromMilliseconds(700), + base::TimeDelta::FromMilliseconds(725), + base::TimeDelta::FromMilliseconds(725), + base::TimeDelta::FromMilliseconds(325), + base::TimeDelta::FromMilliseconds(125), + base::TimeDelta::FromMilliseconds(25), + base::TimeDelta::FromMilliseconds(0)}; + + EXPECT_THAT(client.expected_queueing_times(), + testing::ElementsAreArray(expected_durations)); +} + } // namespace scheduler } // namespace blink
diff --git a/third_party/WebKit/Source/platform/scheduler/renderer/renderer_scheduler_impl.cc b/third_party/WebKit/Source/platform/scheduler/renderer/renderer_scheduler_impl.cc index 09f5c3dd..0a0d3ced 100644 --- a/third_party/WebKit/Source/platform/scheduler/renderer/renderer_scheduler_impl.cc +++ b/third_party/WebKit/Source/platform/scheduler/renderer/renderer_scheduler_impl.cc
@@ -50,6 +50,8 @@ // We do not throttle anything while audio is played and shortly after that. constexpr base::TimeDelta kThrottlingDelayAfterAudioIsPlayed = base::TimeDelta::FromSeconds(5); +constexpr base::TimeDelta kQueueingTimeWindowDuration = + base::TimeDelta::FromSeconds(1); void ReportForegroundRendererTaskLoad(base::TimeTicks time, double load) { if (!blink::RuntimeEnabledFeatures::timerThrottlingForBackgroundTabsEnabled()) @@ -100,7 +102,7 @@ base::Unretained(this)), helper_.ControlTaskQueue()), seqlock_queueing_time_estimator_( - QueueingTimeEstimator(this, base::TimeDelta::FromSeconds(1))), + QueueingTimeEstimator(this, kQueueingTimeWindowDuration, 20)), main_thread_only_(this, compositor_task_queue_, helper_.scheduler_tqm_delegate().get(), @@ -1694,7 +1696,6 @@ base::TimeDelta estimated_queueing_time; bool can_read = false; - QueueingTimeEstimator::State queueing_time_estimator_state; base::subtle::Atomic32 version; seqlock_queueing_time_estimator_.seqlock.TryRead(&can_read, &version); @@ -1704,7 +1705,7 @@ if (!can_read) return GetCompositorThreadOnly().main_thread_seems_unresponsive; - queueing_time_estimator_state = + QueueingTimeEstimator::State queueing_time_estimator_state = seqlock_queueing_time_estimator_.data.GetState(); // If we fail to determine if the main thread is busy, assume whether or not @@ -1855,12 +1856,26 @@ } void RendererSchedulerImpl::OnQueueingTimeForWindowEstimated( - base::TimeDelta queueing_time) { + base::TimeDelta queueing_time, + base::TimeTicks window_start_time) { + // RendererScheduler reports the queueing time once per window's duration. + // |stepEQT|stepEQT|stepEQT|stepEQT|stepEQT|stepEQT| + // Report: |-------window EQT------| + // Discard: |-------window EQT------| + // Discard: |-------window EQT------| + // Report: |-------window EQT------| + if (window_start_time - + GetMainThreadOnly().uma_last_queueing_time_report_window_start_time < + kQueueingTimeWindowDuration) { + return; + } UMA_HISTOGRAM_TIMES("RendererScheduler.ExpectedTaskQueueingDuration", queueing_time); TRACE_COUNTER1(TRACE_DISABLED_BY_DEFAULT("renderer.scheduler"), "estimated_queueing_time_for_window", queueing_time.InMillisecondsF()); + GetMainThreadOnly().uma_last_queueing_time_report_window_start_time = + window_start_time; } AutoAdvancingVirtualTimeDomain* RendererSchedulerImpl::GetVirtualTimeDomain() {
diff --git a/third_party/WebKit/Source/platform/scheduler/renderer/renderer_scheduler_impl.h b/third_party/WebKit/Source/platform/scheduler/renderer/renderer_scheduler_impl.h index 0f3570db..bc13c3f 100644 --- a/third_party/WebKit/Source/platform/scheduler/renderer/renderer_scheduler_impl.h +++ b/third_party/WebKit/Source/platform/scheduler/renderer/renderer_scheduler_impl.h
@@ -140,7 +140,9 @@ void OnBeginNestedRunLoop() override; // QueueingTimeEstimator::Client implementation: - void OnQueueingTimeForWindowEstimated(base::TimeDelta queueing_time) override; + void OnQueueingTimeForWindowEstimated( + base::TimeDelta queueing_time, + base::TimeTicks window_start_time) override; scoped_refptr<TaskQueue> DefaultTaskQueue(); scoped_refptr<TaskQueue> CompositorTaskQueue(); @@ -458,6 +460,7 @@ base::TimeTicks current_policy_expiration_time; base::TimeTicks estimated_next_frame_begin; base::TimeTicks current_task_start_time; + base::TimeTicks uma_last_queueing_time_report_window_start_time; base::TimeDelta compositor_frame_interval; base::TimeDelta longest_jank_free_task_duration; base::Optional<base::TimeTicks> last_audio_state_change;
diff --git a/third_party/WebKit/Source/platform/scheduler/renderer/renderer_scheduler_impl_unittest.cc b/third_party/WebKit/Source/platform/scheduler/renderer/renderer_scheduler_impl_unittest.cc index 5645568..4e00051 100644 --- a/third_party/WebKit/Source/platform/scheduler/renderer/renderer_scheduler_impl_unittest.cc +++ b/third_party/WebKit/Source/platform/scheduler/renderer/renderer_scheduler_impl_unittest.cc
@@ -3826,6 +3826,32 @@ scheduler_->MainThreadSeemsUnresponsive(responsiveness_threshold())); } +// As |responsiveness_threshold| == expected queueing time threshold == 0.2s, +// for a task shorter than the length of the window (1s), the critical value of +// the length of task x can be calculated by (x/2) * (x/1) = 0.2, in which x = +// 0.6324. +TEST_F(RendererSchedulerImplTest, UnresponsiveMainThreadAboveThreshold) { + EXPECT_FALSE( + scheduler_->MainThreadSeemsUnresponsive(responsiveness_threshold())); + + AdvanceTimeWithTask(0.64); + EXPECT_TRUE( + scheduler_->MainThreadSeemsUnresponsive(responsiveness_threshold())); +} + +// As |responsiveness_threshold| == expected queueing time threshold == 0.2s, +// for a task shorter than the length of the window (1s), the critical value of +// the length of task x can be calculated by (x/2) * (x/1) = 0.2, in which x = +// 0.6324. +TEST_F(RendererSchedulerImplTest, ResponsiveMainThreadBelowThreshold) { + EXPECT_FALSE( + scheduler_->MainThreadSeemsUnresponsive(responsiveness_threshold())); + + AdvanceTimeWithTask(0.63); + EXPECT_FALSE( + scheduler_->MainThreadSeemsUnresponsive(responsiveness_threshold())); +} + TEST_F(RendererSchedulerImplTest, ResponsiveMainThreadDuringTask) { EXPECT_FALSE( scheduler_->MainThreadSeemsUnresponsive(responsiveness_threshold()));
diff --git a/third_party/WebKit/Source/platform/weborigin/SecurityOrigin.cpp b/third_party/WebKit/Source/platform/weborigin/SecurityOrigin.cpp index 635b8ef2..8d843bf5 100644 --- a/third_party/WebKit/Source/platform/weborigin/SecurityOrigin.cpp +++ b/third_party/WebKit/Source/platform/weborigin/SecurityOrigin.cpp
@@ -374,8 +374,8 @@ // Changing suborigins midstream is bad. Very bad. It should not happen. // This is, in fact, one of the very basic invariants that makes // suborigins an effective security tool. - RELEASE_ASSERT(suborigin_.GetName().IsNull() || - (suborigin_.GetName() == suborigin.GetName())); + CHECK(suborigin_.GetName().IsNull() || + (suborigin_.GetName() == suborigin.GetName())); suborigin_.SetTo(suborigin); }
diff --git a/third_party/WebKit/Source/platform/weborigin/SecurityOrigin.h b/third_party/WebKit/Source/platform/weborigin/SecurityOrigin.h index d346c9f..4aa9292 100644 --- a/third_party/WebKit/Source/platform/weborigin/SecurityOrigin.h +++ b/third_party/WebKit/Source/platform/weborigin/SecurityOrigin.h
@@ -202,7 +202,7 @@ // Assigns a suborigin namespace to the SecurityOrigin. addSuborigin() must // only ever be called once per SecurityOrigin(). If it is called on a // SecurityOrigin that has already had a suborigin assigned, it will hit a - // RELEASE_ASSERT(). + // CHECK(). bool HasSuborigin() const { return !suborigin_.GetName().IsNull(); } const Suborigin* GetSuborigin() const { return &suborigin_; } void AddSuborigin(const Suborigin&);
diff --git a/third_party/WebKit/Source/web/WebLocalFrameImpl.cpp b/third_party/WebKit/Source/web/WebLocalFrameImpl.cpp index cddba83c..1873df9 100644 --- a/third_party/WebKit/Source/web/WebLocalFrameImpl.cpp +++ b/third_party/WebKit/Source/web/WebLocalFrameImpl.cpp
@@ -1954,7 +1954,8 @@ } void WebLocalFrameImpl::SetCanHaveScrollbars(bool can_have_scrollbars) { - GetFrame()->View()->SetCanHaveScrollbars(can_have_scrollbars); + if (FrameView* view = GetFrameView()) + view->SetCanHaveScrollbars(can_have_scrollbars); } void WebLocalFrameImpl::SetInputEventsTransformForEmulation(
diff --git a/tools/mb/mb_config.pyl b/tools/mb/mb_config.pyl index 57e79d71..a17e5f4 100644 --- a/tools/mb/mb_config.pyl +++ b/tools/mb/mb_config.pyl
@@ -438,26 +438,6 @@ 'Windows Dev': 'debug_bot', }, - # TODO(mmoss): Move these to mb_configs_official.pyl in the release repo - # once the continuous builders are migrated to use recipes from that repo. - 'official.desktop.continuous': { - 'mac beta': 'official', - 'mac stable': 'official', - 'mac trunk': 'official', - 'linux64 beta': 'official_six_concurrent_links', - 'linux64 stable': 'official_six_concurrent_links', - 'linux64 trunk': 'official_six_concurrent_links', - # TODO(mmoss): These precise64 entries can go away once the newly renamed - # builders are fully deployed. - 'precise64 beta': 'official_six_concurrent_links', - 'precise64 stable': 'official_six_concurrent_links', - 'precise64 trunk': 'official_six_concurrent_links', - 'win beta': 'official_six_concurrent_links', - 'win stable': 'official_six_concurrent_links', - 'win trunk': 'official_six_concurrent_links', - 'win64 trunk': 'official_six_concurrent_links', - }, - 'tryserver.blink': { # Most tryservers should have '_trybot' in their config names, but # 'release_trybot' includes 'dcheck_always_on', and the blink @@ -1323,10 +1303,6 @@ 'msan', 'release_bot', ], - 'official': [ - 'official', - ], - 'official_goma_minimal_symbols_clang': [ 'official', 'goma', 'minimal_symbols', 'clang', ], @@ -1371,10 +1347,6 @@ 'official_optimize', 'chrome_pgo_phase_2', 'x86', ], - 'official_six_concurrent_links': [ - 'official', 'six_concurrent_links', - ], - 'release_bot_ozone_linux': [ 'release_bot', 'ozone', 'ozone_linux', ], @@ -1854,12 +1826,6 @@ 'mixins': ['shared', 'release', 'goma'] }, - 'six_concurrent_links': { - # TODO(crbug.com/611491) Adjust the get_concurrent_links script - # to be more conservative so that we don't need this. - 'gn_args': 'concurrent_links=6', - }, - 'static': { 'gn_args': 'is_component_build=false', },
diff --git a/tools/metrics/histograms/histograms.xml b/tools/metrics/histograms/histograms.xml index 441ddd975..3862a2a 100644 --- a/tools/metrics/histograms/histograms.xml +++ b/tools/metrics/histograms/histograms.xml
@@ -642,6 +642,14 @@ </summary> </histogram> +<histogram name="Android.DownloadManager.ShowStorageInfo" enum="BooleanVisible"> + <owner>shaktisahu@chromium.org</owner> + <summary> + Recorded when the user clicks the info button on download home to toggle the + storage info. The state recorded is after the visibility is toggled. + </summary> +</histogram> + <histogram name="Android.DownloadManager.SpaceUsed" units="%"> <owner>dfalcantara@chromium.org</owner> <owner>twellington@chromium.org</owner> @@ -2588,21 +2596,21 @@ </histogram> <histogram name="AsyncDNS.AttemptCountFail"> - <owner>juliatuttle@chromium.org</owner> + <owner>mgersh@chromium.org</owner> <summary> Count of DnsAttempts before DnsTransaction completes with failure. </summary> </histogram> <histogram name="AsyncDNS.AttemptCountSuccess"> - <owner>juliatuttle@chromium.org</owner> + <owner>mgersh@chromium.org</owner> <summary> Count of DnsAttempts before DnsTransaction completes successfully. </summary> </histogram> <histogram name="AsyncDNS.ConfigChange" enum="BooleanSuccess"> - <owner>juliatuttle@chromium.org</owner> + <owner>mgersh@chromium.org</owner> <summary> Whether DnsConfigService::OnConfigChange actually corresponded to a change in DnsConfig. @@ -2610,45 +2618,45 @@ </histogram> <histogram name="AsyncDNS.ConfigNotifyInterval" units="ms"> - <owner>juliatuttle@chromium.org</owner> + <owner>mgersh@chromium.org</owner> <summary> Duration of time between calls to DnsConfigService::InvalidateConfig. </summary> </histogram> <histogram name="AsyncDNS.ConfigParseDuration" units="ms"> - <owner>juliatuttle@chromium.org</owner> + <owner>mgersh@chromium.org</owner> <summary>Duration of time spent parsing DnsConfig.</summary> </histogram> <histogram name="AsyncDNS.ConfigParsePosix" enum="AsyncDNSConfigParsePosix"> - <owner>juliatuttle@chromium.org</owner> + <owner>mgersh@chromium.org</owner> <summary> Counts of results of parsing DnsConfig in DnsConfigServicePosix. </summary> </histogram> <histogram name="AsyncDNS.ConfigParseResult" enum="BooleanSuccess"> - <owner>juliatuttle@chromium.org</owner> + <owner>mgersh@chromium.org</owner> <summary>Whether DnsConfig was parsed successfully.</summary> </histogram> <histogram name="AsyncDNS.ConfigParseWin" enum="AsyncDNSConfigParseWin"> - <owner>juliatuttle@chromium.org</owner> + <owner>mgersh@chromium.org</owner> <summary> Counts of results of parsing DnsConfig in DnsConfigServiceWin. </summary> </histogram> <histogram name="AsyncDNS.DNSChangerDetected" enum="BooleanSuccess"> - <owner>juliatuttle@chromium.org</owner> + <owner>mgersh@chromium.org</owner> <summary> Whether the first valid DnsConfig included a rogue nameserver. </summary> </histogram> <histogram name="AsyncDNS.DnsClientDisabledReason" enum="NetErrorCodes"> - <owner>juliatuttle@chromium.org</owner> + <owner>mgersh@chromium.org</owner> <summary> Counts of specific error codes returned by DnsTask if a subsequent ProcTask succeeded, at the end of a streak of failures after which the DnsClient was @@ -2657,7 +2665,7 @@ </histogram> <histogram name="AsyncDNS.DnsClientEnabled" enum="BooleanSuccess"> - <owner>juliatuttle@chromium.org</owner> + <owner>mgersh@chromium.org</owner> <summary> TRUE counts the events when a valid DnsConfig is received and used to enable DnsClient, while FALSE counts the events when DnsClient is disabled after a @@ -2666,21 +2674,21 @@ </histogram> <histogram name="AsyncDNS.FallbackFail" units="ms"> - <owner>juliatuttle@chromium.org</owner> + <owner>mgersh@chromium.org</owner> <summary> Duration of time spent by ProcTask in failing fallback resolutions. </summary> </histogram> <histogram name="AsyncDNS.FallbackSuccess" units="ms"> - <owner>juliatuttle@chromium.org</owner> + <owner>mgersh@chromium.org</owner> <summary> Duration of time spent by ProcTask in successful fallback resolutions. </summary> </histogram> <histogram name="AsyncDNS.HaveDnsConfig" enum="BooleanSuccess"> - <owner>juliatuttle@chromium.org</owner> + <owner>mgersh@chromium.org</owner> <summary> Whether there was a valid DNS configuration at the start of a job which eventually completed successfully. @@ -2688,12 +2696,12 @@ </histogram> <histogram name="AsyncDNS.HostParseResult" enum="BooleanSuccess"> - <owner>juliatuttle@chromium.org</owner> + <owner>mgersh@chromium.org</owner> <summary>Whether DnsHosts were parsed successfully.</summary> </histogram> <histogram name="AsyncDNS.HostsChange" enum="BooleanSuccess"> - <owner>juliatuttle@chromium.org</owner> + <owner>mgersh@chromium.org</owner> <summary> Whether DnsConfigService::OnHostsChange actually corresponded to a change in DnsHosts. @@ -2701,33 +2709,33 @@ </histogram> <histogram name="AsyncDNS.HostsNotifyInterval" units="ms"> - <owner>juliatuttle@chromium.org</owner> + <owner>mgersh@chromium.org</owner> <summary> Duration of time between calls to DnsConfigService::InvalidateHosts. </summary> </histogram> <histogram name="AsyncDNS.HostsParseDuration" units="ms"> - <owner>juliatuttle@chromium.org</owner> + <owner>mgersh@chromium.org</owner> <summary>Duration of time spent parsing DnsHosts.</summary> </histogram> <histogram name="AsyncDNS.HostsParseWin" enum="AsyncDNSHostsParseWin"> - <owner>juliatuttle@chromium.org</owner> + <owner>mgersh@chromium.org</owner> <summary> Counts of results of parsing DnsHosts in DnsConfigServiceWin. </summary> </histogram> <histogram name="AsyncDNS.HostsSize" units="bytes"> - <owner>juliatuttle@chromium.org</owner> + <owner>mgersh@chromium.org</owner> <summary> The size of the HOSTS file observed before each attempt to parse it. </summary> </histogram> <histogram name="AsyncDNS.JobQueueTime" units="ms"> - <owner>juliatuttle@chromium.org</owner> + <owner>mgersh@chromium.org</owner> <summary> Time elapsed between the time the HostResolverImpl::Job was created and the time the Job was started (using DnsClient). @@ -2735,7 +2743,7 @@ </histogram> <histogram name="AsyncDNS.JobQueueTime_HIGHEST" units="ms"> - <owner>juliatuttle@chromium.org</owner> + <owner>mgersh@chromium.org</owner> <summary> Time elapsed between the time the HostResolverImpl::Job was created and the time the Job was started (using DnsClient). Includes only Jobs which had @@ -2744,7 +2752,7 @@ </histogram> <histogram name="AsyncDNS.JobQueueTime_IDLE" units="ms"> - <owner>juliatuttle@chromium.org</owner> + <owner>mgersh@chromium.org</owner> <summary> Time elapsed between the time the HostResolverImpl::Job was created and the time the Job was started (using DnsClient). Includes only Jobs which had @@ -2753,7 +2761,7 @@ </histogram> <histogram name="AsyncDNS.JobQueueTime_LOW" units="ms"> - <owner>juliatuttle@chromium.org</owner> + <owner>mgersh@chromium.org</owner> <summary> Time elapsed between the time the HostResolverImpl::Job was created and the time the Job was started (using DnsClient). Includes only Jobs which had @@ -2762,7 +2770,7 @@ </histogram> <histogram name="AsyncDNS.JobQueueTime_LOWEST" units="ms"> - <owner>juliatuttle@chromium.org</owner> + <owner>mgersh@chromium.org</owner> <summary> Time elapsed between the time the HostResolverImpl::Job was created and the time the Job was started (using DnsClient). Includes only Jobs which had @@ -2771,7 +2779,7 @@ </histogram> <histogram name="AsyncDNS.JobQueueTime_MEDIUM" units="ms"> - <owner>juliatuttle@chromium.org</owner> + <owner>mgersh@chromium.org</owner> <summary> Time elapsed between the time the HostResolverImpl::Job was created and the time the Job was started (using DnsClient). Includes only Jobs which had @@ -2780,7 +2788,7 @@ </histogram> <histogram name="AsyncDNS.JobQueueTimeAfterChange" units="ms"> - <owner>juliatuttle@chromium.org</owner> + <owner>mgersh@chromium.org</owner> <summary> Time elapsed between the last time the priority of a HostResolverImpl::Job changed (when a Request was attached or detached) and the time the Job was @@ -2789,7 +2797,7 @@ </histogram> <histogram name="AsyncDNS.JobQueueTimeAfterChange_HIGHEST" units="ms"> - <owner>juliatuttle@chromium.org</owner> + <owner>mgersh@chromium.org</owner> <summary> Time elapsed between the last time the priority of a HostResolverImpl::Job changed (when a Request was attached or detached) and the time the Job was @@ -2799,7 +2807,7 @@ </histogram> <histogram name="AsyncDNS.JobQueueTimeAfterChange_IDLE" units="ms"> - <owner>juliatuttle@chromium.org</owner> + <owner>mgersh@chromium.org</owner> <summary> Time elapsed between the last time the priority of a HostResolverImpl::Job changed (when a Request was attached or detached) and the time the Job was @@ -2809,7 +2817,7 @@ </histogram> <histogram name="AsyncDNS.JobQueueTimeAfterChange_LOW" units="ms"> - <owner>juliatuttle@chromium.org</owner> + <owner>mgersh@chromium.org</owner> <summary> Time elapsed between the last time the priority of a HostResolverImpl::Job changed (when a Request was attached or detached) and the time the Job was @@ -2819,7 +2827,7 @@ </histogram> <histogram name="AsyncDNS.JobQueueTimeAfterChange_LOWEST" units="ms"> - <owner>juliatuttle@chromium.org</owner> + <owner>mgersh@chromium.org</owner> <summary> Time elapsed between the last time the priority of a HostResolverImpl::Job changed (when a Request was attached or detached) and the time the Job was @@ -2829,7 +2837,7 @@ </histogram> <histogram name="AsyncDNS.JobQueueTimeAfterChange_MEDIUM" units="ms"> - <owner>juliatuttle@chromium.org</owner> + <owner>mgersh@chromium.org</owner> <summary> Time elapsed between the last time the priority of a HostResolverImpl::Job changed (when a Request was attached or detached) and the time the Job was @@ -2842,7 +2850,7 @@ <obsolete> Deprecated as of 4/2016. </obsolete> - <owner>juliatuttle@chromium.org</owner> + <owner>mgersh@chromium.org</owner> <summary> Type of nameservers in the DNS config, recorded each time the config is read by the DNSConfigService. @@ -2850,7 +2858,7 @@ </histogram> <histogram name="AsyncDNS.ParseToAddressList" enum="AsyncDNSParseResult"> - <owner>juliatuttle@chromium.org</owner> + <owner>mgersh@chromium.org</owner> <summary> Counts of results of parsing addresses out of DNS responses in successful DnsTransactions. @@ -2858,7 +2866,7 @@ </histogram> <histogram name="AsyncDNS.PrefDefaultSource" enum="AsyncDNSPrefDefaultSource"> - <owner>juliatuttle@chromium.org</owner> + <owner>mgersh@chromium.org</owner> <summary> The source of the async DNS preference's default. Logged at startup, when the IO thread is created. @@ -2866,7 +2874,7 @@ </histogram> <histogram name="AsyncDNS.PrefSource" enum="AsyncDNSPrefSource"> - <owner>juliatuttle@chromium.org</owner> + <owner>mgersh@chromium.org</owner> <summary> The source of the async DNS preference's value. Logged at startup, when the IO thread is created. @@ -2874,7 +2882,7 @@ </histogram> <histogram name="AsyncDNS.ResolveError" enum="NetErrorCodes"> - <owner>juliatuttle@chromium.org</owner> + <owner>mgersh@chromium.org</owner> <summary> Counts of specific error codes returned by DnsTask if a subsequent ProcTask succeeded. @@ -2882,7 +2890,7 @@ </histogram> <histogram name="AsyncDNS.ResolveFail" units="ms"> - <owner>juliatuttle@chromium.org</owner> + <owner>mgersh@chromium.org</owner> <summary> Duration of time taken by DnsTask in resolutions that failed. Excludes time spent in the subsequent fallback. @@ -2890,7 +2898,7 @@ </histogram> <histogram name="AsyncDNS.ResolveStatus" enum="AsyncDNSResolveStatus"> - <owner>juliatuttle@chromium.org</owner> + <owner>mgersh@chromium.org</owner> <summary> Counts of the overall results of using asynchronous DNS in HostResolverImpl. This only includes jobs started with valid DNS configuration and excludes @@ -2899,35 +2907,35 @@ </histogram> <histogram name="AsyncDNS.ResolveSuccess" units="ms"> - <owner>juliatuttle@chromium.org</owner> + <owner>mgersh@chromium.org</owner> <summary> Duration of time taken by DnsTask in resolutions that succeeded. </summary> </histogram> <histogram name="AsyncDNS.ResolveSuccess_FAMILY_IPV4" units="ms"> - <owner>juliatuttle@chromium.org</owner> + <owner>mgersh@chromium.org</owner> <summary> Same as AsyncDNS.ResolveSuccess, but limited to pure IPv4 lookups. </summary> </histogram> <histogram name="AsyncDNS.ResolveSuccess_FAMILY_IPV6" units="ms"> - <owner>juliatuttle@chromium.org</owner> + <owner>mgersh@chromium.org</owner> <summary> Same as AsyncDNS.ResolveSuccess, but limited to pure IPv6 lookups. </summary> </histogram> <histogram name="AsyncDNS.ResolveSuccess_FAMILY_UNSPEC" units="ms"> - <owner>juliatuttle@chromium.org</owner> + <owner>mgersh@chromium.org</owner> <summary> Same as AsyncDNS.ResolveSuccess, but limited to IPv4/IPv6 lookups. </summary> </histogram> <histogram name="AsyncDNS.ServerCount"> - <owner>juliatuttle@chromium.org</owner> + <owner>mgersh@chromium.org</owner> <summary> Count of servers in DnsConfig. Recorded on every new DnsSession, which is created on DNS change. @@ -2935,14 +2943,14 @@ </histogram> <histogram name="AsyncDNS.ServerFailureIndex"> - <owner>juliatuttle@chromium.org</owner> + <owner>mgersh@chromium.org</owner> <summary> Index in DnsConfig of the failing server, recorded at the time of failure. </summary> </histogram> <histogram name="AsyncDNS.ServerFailuresAfterNetworkChange"> - <owner>juliatuttle@chromium.org</owner> + <owner>mgersh@chromium.org</owner> <summary> Count of server failures after network change before first success in the DnsSession. Recorded at the time of first success. @@ -2950,7 +2958,7 @@ </histogram> <histogram name="AsyncDNS.ServerFailuresAfterSuccess"> - <owner>juliatuttle@chromium.org</owner> + <owner>mgersh@chromium.org</owner> <summary> Count of server failures after success until the end of the session. Server has reported success at some point during the session. Recorded at the end @@ -2959,7 +2967,7 @@ </histogram> <histogram name="AsyncDNS.ServerFailuresBeforeSuccess"> - <owner>juliatuttle@chromium.org</owner> + <owner>mgersh@chromium.org</owner> <summary> Count of server failures before success. This is NOT the first success in the DnsSession. Recorded at the time of success. @@ -2967,7 +2975,7 @@ </histogram> <histogram name="AsyncDNS.ServerFailuresWithoutSuccess"> - <owner>juliatuttle@chromium.org</owner> + <owner>mgersh@chromium.org</owner> <summary> Count of server failures without success until the end of the session. Server has never reported success during the DnsSession. Recorded at the end @@ -2976,14 +2984,14 @@ </histogram> <histogram name="AsyncDNS.ServerIsGood" enum="BooleanSuccess"> - <owner>juliatuttle@chromium.org</owner> + <owner>mgersh@chromium.org</owner> <summary> The current server is "good" and does not have to be skipped. </summary> </histogram> <histogram name="AsyncDNS.SortFailure" units="ms"> - <owner>juliatuttle@chromium.org</owner> + <owner>mgersh@chromium.org</owner> <summary> Duration of time taken in failing calls to AddressSorter in dual-stack resolutions using DnsTask. @@ -2991,7 +2999,7 @@ </histogram> <histogram name="AsyncDNS.SortSuccess" units="ms"> - <owner>juliatuttle@chromium.org</owner> + <owner>mgersh@chromium.org</owner> <summary> Duration of time taken in successful calls to AddressSorter in dual-stack resolutions using DnsTask. @@ -2999,7 +3007,7 @@ </histogram> <histogram name="AsyncDNS.SuffixSearchDone"> - <owner>juliatuttle@chromium.org</owner> + <owner>mgersh@chromium.org</owner> <summary> The number of names from the search name list consumed during a successful transaction (QTYPE A only). @@ -3007,7 +3015,7 @@ </histogram> <histogram name="AsyncDNS.SuffixSearchRemain"> - <owner>juliatuttle@chromium.org</owner> + <owner>mgersh@chromium.org</owner> <summary> The number of names left on the search name list at the end of a successful transaction (QTYPE A only). @@ -3015,7 +3023,7 @@ </histogram> <histogram name="AsyncDNS.SuffixSearchStart"> - <owner>juliatuttle@chromium.org</owner> + <owner>mgersh@chromium.org</owner> <summary> The number of names on the search name list at the start of a transaction (QTYPE A only). @@ -3023,7 +3031,7 @@ </histogram> <histogram name="AsyncDNS.TCPAttemptFail" units="ms"> - <owner>juliatuttle@chromium.org</owner> + <owner>mgersh@chromium.org</owner> <summary> Duration of time taken by DnsTCPAttempt in failed attempts. Excludes timeouts. @@ -3031,42 +3039,42 @@ </histogram> <histogram name="AsyncDNS.TCPAttemptSuccess" units="ms"> - <owner>juliatuttle@chromium.org</owner> + <owner>mgersh@chromium.org</owner> <summary> Duration of time taken by DnsTCPAttempt in successful attempts. </summary> </histogram> <histogram name="AsyncDNS.TimeoutErrorHistogram" units="ms"> - <owner>juliatuttle@chromium.org</owner> + <owner>mgersh@chromium.org</owner> <summary> Difference between RTT and timeout calculated using Histogram algorithm. </summary> </histogram> <histogram name="AsyncDNS.TimeoutErrorHistogramUnder" units="ms"> - <owner>juliatuttle@chromium.org</owner> + <owner>mgersh@chromium.org</owner> <summary> Difference between timeout calculated using Histogram algorithm and RTT. </summary> </histogram> <histogram name="AsyncDNS.TimeoutErrorJacobson" units="ms"> - <owner>juliatuttle@chromium.org</owner> + <owner>mgersh@chromium.org</owner> <summary> Difference between RTT and timeout calculated using Jacobson algorithm. </summary> </histogram> <histogram name="AsyncDNS.TimeoutErrorJacobsonUnder" units="ms"> - <owner>juliatuttle@chromium.org</owner> + <owner>mgersh@chromium.org</owner> <summary> Difference between timeout calculated using Jacobson algorithm and RTT. </summary> </histogram> <histogram name="AsyncDNS.TimeoutSpentHistogram" units="ms"> - <owner>juliatuttle@chromium.org</owner> + <owner>mgersh@chromium.org</owner> <summary> Duration of time that would be spent waiting for lost request using Histogram algorithm. @@ -3074,7 +3082,7 @@ </histogram> <histogram name="AsyncDNS.TimeoutSpentJacobson" units="ms"> - <owner>juliatuttle@chromium.org</owner> + <owner>mgersh@chromium.org</owner> <summary> Duration of time that would be spent waiting for lost request using Jacobson algorithm. @@ -3082,7 +3090,7 @@ </histogram> <histogram name="AsyncDNS.TotalTime" units="ms"> - <owner>juliatuttle@chromium.org</owner> + <owner>mgersh@chromium.org</owner> <summary> Duration of time since a HostResolverImpl::Resolve request to the time a result is posted. Excludes canceled, evicted, and aborted requests. Includes @@ -3091,7 +3099,7 @@ </histogram> <histogram name="AsyncDNS.TotalTime_speculative" units="ms"> - <owner>juliatuttle@chromium.org</owner> + <owner>mgersh@chromium.org</owner> <summary> Duration of time since a HostResolverImpl::Resolve request to the time a result is posted. Excludes canceled, evicted, and aborted requests. Includes @@ -3100,7 +3108,7 @@ </histogram> <histogram name="AsyncDNS.TransactionFailure" units="ms"> - <owner>juliatuttle@chromium.org</owner> + <owner>mgersh@chromium.org</owner> <summary> Duration of time taken in failing DnsTransactions. This includes server failures, timeouts and NXDOMAIN results. @@ -3108,7 +3116,7 @@ </histogram> <histogram name="AsyncDNS.TransactionSuccess" units="ms"> - <owner>juliatuttle@chromium.org</owner> + <owner>mgersh@chromium.org</owner> <summary> Duration of time taken in successful DnsTransactions. This includes all NOERROR answers, even if they indicate the name has no addresses or they @@ -3117,21 +3125,21 @@ </histogram> <histogram name="AsyncDNS.TransactionSuccess_A" units="ms"> - <owner>juliatuttle@chromium.org</owner> + <owner>mgersh@chromium.org</owner> <summary> Same as AsyncDNS.TransactionSuccess but limited to A query type. </summary> </histogram> <histogram name="AsyncDNS.TransactionSuccess_AAAA" units="ms"> - <owner>juliatuttle@chromium.org</owner> + <owner>mgersh@chromium.org</owner> <summary> Same as AsyncDNS.TransactionSuccess but limited to AAAA query type. </summary> </histogram> <histogram name="AsyncDNS.TTL" units="ms"> - <owner>juliatuttle@chromium.org</owner> + <owner>mgersh@chromium.org</owner> <summary> TTL of the resolved addresses, as in the response received from the server. For results served from local cache, the TTL is from the original response. @@ -3139,7 +3147,7 @@ </histogram> <histogram name="AsyncDNS.UDPAttemptFail" units="ms"> - <owner>juliatuttle@chromium.org</owner> + <owner>mgersh@chromium.org</owner> <summary> Duration of time taken by DnsUDPAttempt in failed attempts. Excludes timeouts. @@ -3147,7 +3155,7 @@ </histogram> <histogram name="AsyncDNS.UDPAttemptSuccess" units="ms"> - <owner>juliatuttle@chromium.org</owner> + <owner>mgersh@chromium.org</owner> <summary> Duration of time taken by DnsUDPAttempt in successful attempts. Includes responses arriving after timeout, if multiple attempts are allowed. @@ -3155,7 +3163,7 @@ </histogram> <histogram name="AsyncDNS.UnchangedConfigInterval" units="ms"> - <owner>juliatuttle@chromium.org</owner> + <owner>mgersh@chromium.org</owner> <summary> Duration of time since the last empty config result to the time a non-change OnConfigChange is received. @@ -3163,7 +3171,7 @@ </histogram> <histogram name="AsyncDNS.UnchangedHostsInterval" units="ms"> - <owner>juliatuttle@chromium.org</owner> + <owner>mgersh@chromium.org</owner> <summary> Duration of time since the last empty config result to the time a non-change OnHostsChange is received. @@ -3171,7 +3179,7 @@ </histogram> <histogram name="AsyncDNS.WatchStatus" enum="AsyncDNSWatchStatus"> - <owner>juliatuttle@chromium.org</owner> + <owner>mgersh@chromium.org</owner> <summary> The result of DnsConfigService watch. Counts STARTED on every initialization and FAILED_* on any failure. @@ -16013,6 +16021,26 @@ </summary> </histogram> +<histogram name="Event.Latency.BlockingTime.KeyPressDefaultAllowed" units="ms"> + <owner>tdresser@chromium.org</owner> + <owner>input-dev@chromium.org</owner> + <summary> + Time between the renderer main thread receiving a keyboard event and acking + it, for events which were not preventDefaulted. Only recorded for key + presses. + </summary> +</histogram> + +<histogram name="Event.Latency.BlockingTime.KeyPressDefaultPrevented" + units="ms"> + <owner>tdresser@chromium.org</owner> + <owner>input-dev@chromium.org</owner> + <summary> + Time between the renderer main thread receiving a keyboard event and acking + it, for events which were preventDefaulted. Only recorded for key presses. + </summary> +</histogram> + <histogram name="Event.Latency.BlockingTime.TouchEndDefaultAllowed" units="ms"> <owner>tdresser@chromium.org</owner> <summary> @@ -16439,6 +16467,24 @@ </summary> </histogram> +<histogram name="Event.Latency.Browser.KeyPressAcked" units="microseconds"> + <owner>tdresser@chromium.org</owner> + <owner>input-dev@chromium.org</owner> + <summary> + Time between key events sent from RWH to renderer and acked by renderer. + Only monitors key presses. + </summary> +</histogram> + +<histogram name="Event.Latency.Browser.KeyPressUI" units="microseconds"> + <owner>tdresser@chromium.org</owner> + <owner>input-dev@chromium.org</owner> + <summary> + Time between key events received by Chrome and sent from RWH to renderer. + Only monitors key presses. + </summary> +</histogram> + <histogram name="Event.Latency.Browser.TouchAcked" units="microseconds"> <owner>tdresser@chromium.org</owner> <summary> @@ -16475,6 +16521,16 @@ </summary> </histogram> +<histogram name="Event.Latency.EndToEnd.Key" units="ms"> + <owner>tdresser@chromium.org</owner> + <owner>input-dev@chromium.org</owner> + <summary> + Time between the OS receiving a keyboard event and the resulting GPU frame + swap. If no swap was induced by the event, no recording is made. Only + recorded for key presses. + </summary> +</histogram> + <histogram name="Event.Latency.HitTest" units="microseconds"> <owner>dtapuska@chromium.org</owner> <summary> @@ -16502,6 +16558,27 @@ <summary>Time between input event received by OS and sent to Chrome.</summary> </histogram> +<histogram name="Event.Latency.QueueingTime.KeyPressDefaultAllowed" units="ms"> + <owner>tdresser@chromium.org</owner> + <owner>input-dev@chromium.org</owner> + <summary> + Time between sending a keyboard event to the renderer main thread and when + the renderer begins to process that event, for events which were not + preventDefaulted. Only recorded for key presses. + </summary> +</histogram> + +<histogram name="Event.Latency.QueueingTime.KeyPressDefaultPrevented" + units="ms"> + <owner>tdresser@chromium.org</owner> + <owner>input-dev@chromium.org</owner> + <summary> + Time between sending a keyboard event to the renderer main thread and when + the renderer begins to process that event, for events which were + preventDefaulted. Only recorded for key presses. + </summary> +</histogram> + <histogram name="Event.Latency.QueueingTime.TouchEndDefaultAllowed" units="ms"> <owner>tdresser@chromium.org</owner> <summary> @@ -47426,7 +47503,8 @@ units="Ad frames"> <owner>jkarlin@chromium.org</owner> <summary> - The number of frames on the page identified as Google Ad Frames. + The number of frames on the page identified as Google Ad Frames that have + loaded more than 0 bytes of content. For pages with zero ad frames, the other PageLoad.Clients.Ads metrics are not recorded unless otherwise specified. @@ -47438,6 +47516,9 @@ <histogram name="PageLoad.Clients.Ads.Google.FrameCounts.MainFrameParent.AdFrames" units="Frames"> + <obsolete> + Deprecated In May 2017. + </obsolete> <owner>jkarlin@chromium.org</owner> <summary> The number of frames (with parent frame of main frame) that are on the page @@ -47451,6 +47532,9 @@ <histogram name="PageLoad.Clients.Ads.Google.FrameCounts.MainFrameParent.PercentAdFrames" units="%"> + <obsolete> + Deprecated In May 2017. + </obsolete> <owner>jkarlin@chromium.org</owner> <summary> The percentage of frames (with parent frame of main frame) on the page that @@ -47465,6 +47549,9 @@ <histogram name="PageLoad.Clients.Ads.Google.FrameCounts.MainFrameParent.TotalFrames" units="Frames"> + <obsolete> + Deprecated In May 2017. + </obsolete> <owner>jkarlin@chromium.org</owner> <summary> The number of frames (with parent frame of main frame) on the page.
diff --git a/tools/perf/benchmark.csv b/tools/perf/benchmark.csv index b040b25f..3408224 100644 --- a/tools/perf/benchmark.csv +++ b/tools/perf/benchmark.csv
@@ -129,7 +129,6 @@ startup.warm.chrome_signin,, storage.indexeddb_endure,cmumford@chromium.org, storage.indexeddb_endure_tracing,cmumford@chromium.org, -sunspider,"bmeurer@chromium.org, mvstanton@chromium.org", system_health.common_desktop,"charliea@chromium.org, nednguyen@chromium.org", system_health.common_mobile,"charliea@chromium.org, nednguyen@chromium.org", system_health.memory_desktop,perezju@chromium.org,
diff --git a/tools/perf/benchmarks/sunspider.py b/tools/perf/benchmarks/sunspider.py deleted file mode 100644 index 31916b2..0000000 --- a/tools/perf/benchmarks/sunspider.py +++ /dev/null
@@ -1,150 +0,0 @@ -# Copyright 2013 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. -import collections -import json -import os - -from core import perf_benchmark - -from telemetry import benchmark -from telemetry import page as page_module -from telemetry.page import legacy_page_test -from telemetry import story -from telemetry.value import list_of_scalar_values - -from metrics import power - - -_URL = 'http://www.webkit.org/perf/sunspider-1.0.2/sunspider-1.0.2/driver.html' - -DESCRIPTIONS = { - '3d-cube': - 'Pure JavaScript computations of the kind you might use to do 3d ' - 'rendering, but without the rendering. This ends up mostly hitting ' - 'floating point math and array access.', - '3d-morph': - 'Pure JavaScript computations of the kind you might use to do 3d ' - 'rendering, but without the rendering. This ends up mostly hitting ' - 'floating point math and array access.', - '3d-raytrace': - 'Pure JavaScript computations of the kind you might use to do 3d ' - 'rendering, but without the rendering. This ends up mostly hitting ' - 'floating point math and array access.', - 'access-binary-trees': 'Array, object property and variable access.', - 'access-fannkuch': 'Array, object property and variable access.', - 'access-nbody': 'Array, object property and variable access.', - 'access-nsieve': 'Array, object property and variable access.', - 'bitops-3bit-bits-in-byte': - 'Bitwise operations, these can be useful for various things ' - 'including games, mathematical computations, and various kinds of ' - 'encoding/decoding. It\'s also the only kind of math in JavaScript ' - 'that is done as integer, not floating point.', - 'bitops-bits-in-byte': - 'Bitwise operations, these can be useful for various things ' - 'including games, mathematical computations, and various kinds of ' - 'encoding/decoding. It\'s also the only kind of math in JavaScript ' - 'that is done as integer, not floating point.', - 'bitops-bitwise-and': - 'Bitwise operations, these can be useful for various things ' - 'including games, mathematical computations, and various kinds of ' - 'encoding/decoding. It\'s also the only kind of math in JavaScript ' - 'that is done as integer, not floating point.', - 'bitops-nsieve-bits': - 'Bitwise operations, these can be useful for various things ' - 'including games, mathematical computations, and various kinds of ' - 'encoding/decoding. It\'s also the only kind of math in JavaScript ' - 'that is done as integer, not floating point.', - 'controlflow-recursive': - 'Control flow constructs (looping, recursion, conditionals). Right ' - 'now it mostly covers recursion, as the others are pretty well covered ' - 'by other tests.', - 'crypto-aes': 'Real cryptography code related to AES.', - 'crypto-md5': 'Real cryptography code related to MD5.', - 'crypto-sha1': 'Real cryptography code related to SHA1.', - 'date-format-tofte': 'Performance of JavaScript\'s "date" objects.', - 'date-format-xparb': 'Performance of JavaScript\'s "date" objects.', - 'math-cordic': 'Various mathematical type computations.', - 'math-partial-sums': 'Various mathematical type computations.', - 'math-spectral-norm': 'Various mathematical type computations.', - 'regexp-dna': 'Regular expressions performance.', - 'string-base64': 'String processing.', - 'string-fasta': 'String processing', - 'string-tagcloud': 'String processing code to generate a giant "tagcloud".', - 'string-unpack-code': 'String processing code to extracting compressed JS.', - 'string-validate-input': 'String processing.', -} - - -class _SunspiderMeasurement(legacy_page_test.LegacyPageTest): - - def __init__(self): - super(_SunspiderMeasurement, self).__init__() - self._power_metric = None - - def CustomizeBrowserOptions(self, options): - power.PowerMetric.CustomizeBrowserOptions(options) - - def WillStartBrowser(self, platform): - self._power_metric = power.PowerMetric(platform) - - def DidNavigateToPage(self, page, tab): - self._power_metric.Start(page, tab) - - def ValidateAndMeasurePage(self, page, tab, results): - tab.WaitForJavaScriptCondition( - 'window.location.pathname.indexOf("results.html") >= 0' - '&& typeof(output) != "undefined"', timeout=300) - - self._power_metric.Stop(page, tab) - self._power_metric.AddResults(tab, results) - - js_results = json.loads(tab.EvaluateJavaScript('JSON.stringify(output);')) - - # Below, r is a map of benchmark names to lists of result numbers, - # and totals is a list of totals of result numbers. - # js_results is: formatted like this: - # [ - # {'3d-cube': v1, '3d-morph': v2, ...}, - # {'3d-cube': v3, '3d-morph': v4, ...}, - # ... - # ] - r = collections.defaultdict(list) - totals = [] - for result in js_results: - total = 0 - for key, value in result.iteritems(): - r[key].append(value) - total += value - totals.append(total) - for key, values in r.iteritems(): - results.AddValue(list_of_scalar_values.ListOfScalarValues( - results.current_page, key, 'ms', values, important=False, - description=DESCRIPTIONS.get(key))) - results.AddValue(list_of_scalar_values.ListOfScalarValues( - results.current_page, 'Total', 'ms', totals, - description='Totals of run time for each different type of benchmark ' - 'in sunspider')) - - -@benchmark.Disabled('all') # crbug.com/712208 -@benchmark.Owner(emails=['bmeurer@chromium.org', 'mvstanton@chromium.org']) -class Sunspider(perf_benchmark.PerfBenchmark): - """Apple's SunSpider JavaScript benchmark. - - http://www.webkit.org/perf/sunspider/sunspider.html - """ - test = _SunspiderMeasurement - - @classmethod - def Name(cls): - return 'sunspider' - - def CreateStorySet(self, options): - ps = story.StorySet( - archive_data_file='../page_sets/data/sunspider.json', - base_dir=os.path.dirname(os.path.abspath(__file__)), - cloud_storage_bucket=story.PARTNER_BUCKET) - ps.AddStory(page_module.Page( - _URL, ps, ps.base_dir, make_javascript_deterministic=False)) - return ps
diff --git a/tools/perf/page_sets/system_health/browsing_stories.py b/tools/perf/page_sets/system_health/browsing_stories.py index e949881..75ba50a2 100644 --- a/tools/perf/page_sets/system_health/browsing_stories.py +++ b/tools/perf/page_sets/system_health/browsing_stories.py
@@ -199,7 +199,6 @@ SUPPORTED_PLATFORMS = platforms.MOBILE_ONLY -@decorators.Disabled('mac') # crbug.com/722094 class TwitterMobileStory(_ArticleBrowsingStory): NAME = 'browse:social:twitter' URL = 'https://www.twitter.com/nasa'
diff --git a/ui/aura/BUILD.gn b/ui/aura/BUILD.gn index f0d256a..1fa2766 100644 --- a/ui/aura/BUILD.gn +++ b/ui/aura/BUILD.gn
@@ -62,6 +62,8 @@ "env_input_state_controller.cc", "env_input_state_controller.h", "env_observer.h", + "event_injector.cc", + "event_injector.h", "input_state_lookup.cc", "input_state_lookup.h", "input_state_lookup_win.cc",
diff --git a/ui/aura/env.h b/ui/aura/env.h index 31f7366..303e7b6 100644 --- a/ui/aura/env.h +++ b/ui/aura/env.h
@@ -114,6 +114,7 @@ private: friend class test::EnvTestHelper; + friend class EventInjector; friend class MusMouseLocationUpdater; friend class Window; friend class WindowTreeHost;
diff --git a/ui/aura/event_injector.cc b/ui/aura/event_injector.cc new file mode 100644 index 0000000..09019d0d --- /dev/null +++ b/ui/aura/event_injector.cc
@@ -0,0 +1,61 @@ +// Copyright 2017 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. + +#include "ui/aura/event_injector.h" + +#include "services/service_manager/public/cpp/connector.h" +#include "services/ui/public/interfaces/constants.mojom.h" +#include "ui/aura/env.h" +#include "ui/aura/mus/window_tree_client.h" +#include "ui/aura/window_tree_host.h" +#include "ui/display/display.h" +#include "ui/display/screen.h" +#include "ui/events/event.h" +#include "ui/events/event_sink.h" + +namespace { +std::unique_ptr<ui::Event> MapEvent(const ui::Event& event) { + if (event.IsScrollEvent()) { + return base::MakeUnique<ui::PointerEvent>( + ui::MouseWheelEvent(*event.AsScrollEvent())); + } + + if (event.IsMouseEvent()) + return base::MakeUnique<ui::PointerEvent>(*event.AsMouseEvent()); + + if (event.IsTouchEvent()) + return base::MakeUnique<ui::PointerEvent>(*event.AsTouchEvent()); + + return ui::Event::Clone(event); +} + +} // namespace + +namespace aura { + +EventInjector::EventInjector() {} + +EventInjector::~EventInjector() {} + +ui::EventDispatchDetails EventInjector::Inject(WindowTreeHost* host, + ui::Event* event) { + Env* env = Env::GetInstance(); + DCHECK(env); + DCHECK(host); + DCHECK(event); + + if (env->mode() == Env::Mode::LOCAL) + return host->event_sink()->OnEventFromSource(event); + if (!window_server_ptr_) { + env->window_tree_client_->connector()->BindInterface( + ui::mojom::kServiceName, &window_server_ptr_); + } + display::Screen* screen = display::Screen::GetScreen(); + window_server_ptr_->DispatchEvent( + screen->GetDisplayNearestWindow(host->window()).id(), MapEvent(*event), + base::Bind([](bool result) { DCHECK(result); })); + return ui::EventDispatchDetails(); +} + +} // namespace aura
diff --git a/ui/aura/event_injector.h b/ui/aura/event_injector.h new file mode 100644 index 0000000..a1da299 --- /dev/null +++ b/ui/aura/event_injector.h
@@ -0,0 +1,38 @@ +// Copyright 2017 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. + +#ifndef UI_AURA_EVENT_INJECTOR_H_ +#define UI_AURA_EVENT_INJECTOR_H_ + +#include "services/ui/public/interfaces/window_server_test.mojom.h" +#include "ui/aura/aura_export.h" + +namespace ui { +class Event; +struct EventDispatchDetails; +} + +namespace aura { + +class WindowTreeHost; + +// Used to inject events into the system. In LOCAL mode, it directly injects +// events into the WindowTreeHost, but in MUS mode, it injects events into the +// window-server (over the mojom API). +class AURA_EXPORT EventInjector { + public: + EventInjector(); + ~EventInjector(); + + ui::EventDispatchDetails Inject(WindowTreeHost* host, ui::Event* event); + + private: + ui::mojom::WindowServerTestPtr window_server_ptr_; + + DISALLOW_COPY_AND_ASSIGN(EventInjector); +}; + +} // namespace aura + +#endif // UI_AURA_EVENT_INJECTOR_H_
diff --git a/ui/events/event.cc b/ui/events/event.cc index ce99ff82..249781f 100644 --- a/ui/events/event.cc +++ b/ui/events/event.cc
@@ -149,13 +149,18 @@ case ET_SCROLL_FLING_CANCEL: return SourceEventType::UNKNOWN; + case ui::ET_KEY_PRESSED: + return ui::SourceEventType::KEY_PRESS; + case ET_MOUSE_PRESSED: case ET_MOUSE_DRAGGED: case ET_MOUSE_RELEASED: case ET_MOUSE_MOVED: case ET_MOUSE_ENTERED: case ET_MOUSE_EXITED: - case ET_KEY_PRESSED: + // We measure latency for key presses, not key releases. Most behavior is + // keyed off of presses, and release latency is higher than press latency as + // it's impacted by event handling of the press event. case ET_KEY_RELEASED: case ET_MOUSE_CAPTURE_CHANGED: case ET_DROP_TARGET_EVENT: @@ -1141,6 +1146,11 @@ key_code_(KeyboardCodeFromNative(native_event)), code_(CodeFromNative(native_event)), is_char_(IsCharFromNative(native_event)) { + latency()->AddLatencyNumberWithTimestamp( + INPUT_EVENT_LATENCY_ORIGINAL_COMPONENT, 0, 0, + base::TimeTicks::FromInternalValue(time_stamp().ToInternalValue()), 1); + latency()->AddLatencyNumber(INPUT_EVENT_LATENCY_UI_COMPONENT, 0, 0); + if (IsRepeated(*this)) set_flags(flags() | ui::EF_IS_REPEAT);
diff --git a/ui/events/ozone/gamepad/gamepad_event.h b/ui/events/ozone/gamepad/gamepad_event.h index c0c5349..61e32bd 100644 --- a/ui/events/ozone/gamepad/gamepad_event.h +++ b/ui/events/ozone/gamepad/gamepad_event.h
@@ -18,15 +18,15 @@ double value, base::TimeTicks timestamp); - int device_id() { return device_id_; } + int device_id() const { return device_id_; } - GamepadEventType type() { return type_; } + GamepadEventType type() const { return type_; } - uint16_t code() { return code_; } + uint16_t code() const { return code_; } - double value() { return value_; } + double value() const { return value_; } - base::TimeTicks timestamp() { return timestamp_; } + base::TimeTicks timestamp() const { return timestamp_; } private: int device_id_;
diff --git a/ui/latency/latency_info.h b/ui/latency/latency_info.h index 84c5434..0f8b6be 100644 --- a/ui/latency/latency_info.h +++ b/ui/latency/latency_info.h
@@ -109,6 +109,7 @@ UNKNOWN, WHEEL, TOUCH, + KEY_PRESS, OTHER, SOURCE_EVENT_TYPE_LAST = OTHER, };
diff --git a/ui/latency/latency_tracker.cc b/ui/latency/latency_tracker.cc index 20a30f1..d402506d 100644 --- a/ui/latency/latency_tracker.cc +++ b/ui/latency/latency_tracker.cc
@@ -18,6 +18,8 @@ return "Wheel"; case ui::SourceEventType::TOUCH: return "Touch"; + case ui::SourceEventType::KEY_PRESS: + return "KeyPress"; default: return ""; } @@ -92,9 +94,10 @@ ui::SourceEventType source_event_type = latency.source_event_type(); if (source_event_type == ui::SourceEventType::WHEEL || - source_event_type == ui::SourceEventType::TOUCH) { - ComputeTouchAndWheelScrollLatencyHistograms( - gpu_swap_begin_component, gpu_swap_end_component, latency); + source_event_type == ui::SourceEventType::TOUCH || + source_event_type == ui::SourceEventType::KEY_PRESS) { + ComputeEndToEndLatencyHistograms(gpu_swap_begin_component, + gpu_swap_end_component, latency); } // Compute the old scroll update latency metrics. They are exclusively @@ -117,7 +120,7 @@ // Mus. } -void LatencyTracker::ComputeTouchAndWheelScrollLatencyHistograms( +void LatencyTracker::ComputeEndToEndLatencyHistograms( const ui::LatencyInfo::LatencyComponent& gpu_swap_begin_component, const ui::LatencyInfo::LatencyComponent& gpu_swap_end_component, const ui::LatencyInfo& latency) { @@ -168,6 +171,13 @@ "Event.Latency.ScrollUpdate.Touch.TimeToScrollUpdateSwapBegin2", original_component, gpu_swap_begin_component); } + } else if (latency.FindLatency(ui::INPUT_EVENT_LATENCY_ORIGINAL_COMPONENT, 0, + &original_component)) { + if (input_modality == "KeyPress") { + UMA_HISTOGRAM_INPUT_LATENCY_HIGH_RESOLUTION_MICROSECONDS( + "Event.Latency.EndToEnd.KeyPress", original_component, + gpu_swap_begin_component); + } } else { // No original component found. return;
diff --git a/ui/latency/latency_tracker.h b/ui/latency/latency_tracker.h index 0fae6d3..4d0a432 100644 --- a/ui/latency/latency_tracker.h +++ b/ui/latency/latency_tracker.h
@@ -29,7 +29,7 @@ const LatencyInfo::LatencyComponent& end_component); private: - void ComputeTouchAndWheelScrollLatencyHistograms( + void ComputeEndToEndLatencyHistograms( const LatencyInfo::LatencyComponent& gpu_swap_begin_component, const LatencyInfo::LatencyComponent& gpu_swap_end_component, const LatencyInfo& latency);
diff --git a/ui/latency/mojo/latency_info.mojom b/ui/latency/mojo/latency_info.mojom index 0b985e2..44be9a7 100644 --- a/ui/latency/mojo/latency_info.mojom +++ b/ui/latency/mojo/latency_info.mojom
@@ -79,6 +79,7 @@ UNKNOWN, WHEEL, TOUCH, + KEY_PRESS, OTHER, SOURCE_EVENT_TYPE_LAST = OTHER, };
diff --git a/ui/latency/mojo/latency_info_struct_traits.cc b/ui/latency/mojo/latency_info_struct_traits.cc index e07ecc51..12daf334 100644 --- a/ui/latency/mojo/latency_info_struct_traits.cc +++ b/ui/latency/mojo/latency_info_struct_traits.cc
@@ -160,6 +160,8 @@ return ui::mojom::SourceEventType::WHEEL; case ui::TOUCH: return ui::mojom::SourceEventType::TOUCH; + case ui::KEY_PRESS: + return ui::mojom::SourceEventType::KEY_PRESS; case ui::OTHER: return ui::mojom::SourceEventType::OTHER; } @@ -175,6 +177,8 @@ return ui::WHEEL; case ui::mojom::SourceEventType::TOUCH: return ui::TOUCH; + case ui::mojom::SourceEventType::KEY_PRESS: + return ui::KEY_PRESS; case ui::mojom::SourceEventType::OTHER: return ui::OTHER; }