Commit beabc89c authored by Ted Choc's avatar Ted Choc Committed by Commit Bot

Convert delete suggestion dialog to the Modal Dialog Manager.

BUG=898522

Change-Id: I3a52ec99bde43584203de8bce30b448d50411061
Reviewed-on: https://chromium-review.googlesource.com/c/1318571Reviewed-by: default avatarBecky Zhou <huayinz@chromium.org>
Commit-Queue: Ted Choc <tedchoc@chromium.org>
Cr-Commit-Position: refs/heads/master@{#607107}
parent abcd4da5
......@@ -265,7 +265,6 @@ public abstract class ChromeActivity<C extends ChromeActivityComponent>
private ContextualSearchManager mContextualSearchManager;
protected ReaderModeManager mReaderModeManager;
private SnackbarManager mSnackbarManager;
private ModalDialogManager mModalDialogManager;
private DataReductionPromoSnackbarController mDataReductionPromoSnackbarController;
private AppMenuPropertiesDelegate mAppMenuPropertiesDelegate;
private AppMenuHandler mAppMenuHandler;
......@@ -469,8 +468,6 @@ public abstract class ChromeActivity<C extends ChromeActivityComponent>
.initialize(mFullscreenManager,
mManualFillingController.getKeyboardExtensionSizeManager());
mModalDialogManager = createModalDialogManager();
// If onStart was called before postLayoutInflation (because inflation was done in a
// background thread) then make sure to call the relevant methods belatedly.
if (mStarted) {
......@@ -1283,11 +1280,6 @@ public abstract class ChromeActivity<C extends ChromeActivityComponent>
mContextualSearchManager = null;
}
if (mModalDialogManager != null) {
mModalDialogManager.destroy();
mModalDialogManager = null;
}
if (mTabModelSelectorTabObserver != null) {
mTabModelSelectorTabObserver.destroy();
mTabModelSelectorTabObserver = null;
......@@ -1376,29 +1368,12 @@ public abstract class ChromeActivity<C extends ChromeActivityComponent>
: mSnackbarManager;
}
/**
* @return The {@link ModalDialogManager} created for this class.
*/
@Override
protected ModalDialogManager createModalDialogManager() {
return new ModalDialogManager(
new AppModalPresenter(this), ModalDialogManager.ModalDialogType.APP);
}
/**
* @return The {@link ModalDialogManager} that manages the display of modal dialogs (e.g.
* JavaScript dialogs).
*/
public ModalDialogManager getModalDialogManager() {
return mModalDialogManager;
}
/**
* Sets the modal dialog mangaer.
*/
public void setModalDialogManager(ModalDialogManager modalDialogManager) {
mModalDialogManager = modalDialogManager;
}
protected Drawable getBackgroundDrawable() {
return new ColorDrawable(
ApiCompatibilityUtils.getColor(getResources(), R.color.light_background_color));
......
......@@ -2015,11 +2015,6 @@ public class ChromeTabbedActivity
mUndoBarPopupController = null;
}
if (mTabModalHandler != null) {
mTabModalHandler.destroy();
mTabModalHandler = null;
}
if (mNavigationBarColorController != null) mNavigationBarColorController.destroy();
IncognitoTabHostRegistry.getInstance().unregister(mIncognitoTabHost);
......
......@@ -40,6 +40,7 @@ import org.chromium.chrome.browser.IntentHandler;
import org.chromium.chrome.browser.LaunchIntentDispatcher;
import org.chromium.chrome.browser.WarmupManager;
import org.chromium.chrome.browser.firstrun.FirstRunFlowSequencer;
import org.chromium.chrome.browser.modaldialog.ModalDialogManager;
import org.chromium.chrome.browser.profiles.Profile;
import org.chromium.chrome.browser.tabmodel.DocumentModeAssassin;
import org.chromium.chrome.browser.upgrade.UpgradeActivity;
......@@ -72,6 +73,7 @@ public abstract class AsyncInitializationActivity extends AppCompatActivity impl
private long mOnCreateTimestampUptimeMs;
private ActivityWindowAndroid mWindowAndroid;
private ModalDialogManager mModalDialogManager;
private Bundle mSavedInstanceState;
private int mCurrentOrientation = Surface.ROTATION_0;
private boolean mDestroyed;
......@@ -103,6 +105,11 @@ public abstract class AsyncInitializationActivity extends AppCompatActivity impl
mWindowAndroid = null;
}
if (mModalDialogManager != null) {
mModalDialogManager.destroy();
mModalDialogManager = null;
}
super.onDestroy();
mLifecycleDispatcher.dispatchOnDestroy();
}
......@@ -313,6 +320,7 @@ public abstract class AsyncInitializationActivity extends AppCompatActivity impl
if (mWindowAndroid != null) {
getWindowAndroid().restoreInstanceState(getSavedInstanceState());
}
mModalDialogManager = createModalDialogManager();
mStartupDelayed = shouldDelayBrowserStartup();
ChromeBrowserInitializer.getInstance(this).handlePreNativeStartup(this);
......@@ -363,14 +371,6 @@ public abstract class AsyncInitializationActivity extends AppCompatActivity impl
return mStartupDelayed;
}
/**
* Creates an {@link ActivityWindowAndroid} to delegate calls to, if the Activity requires it.
*/
@Nullable
protected ActivityWindowAndroid createWindowAndroid() {
return null;
}
/**
* @return Whether the browser startup should be delayed. Note that changing this return value
* will have direct impact on startup performance.
......@@ -567,6 +567,14 @@ public abstract class AsyncInitializationActivity extends AppCompatActivity impl
return getIntent();
}
/**
* Creates an {@link ActivityWindowAndroid} to delegate calls to, if the Activity requires it.
*/
@Nullable
protected ActivityWindowAndroid createWindowAndroid() {
return null;
}
/**
* @return A {@link ActivityWindowAndroid} instance. May be null if one was not created.
*/
......@@ -575,6 +583,29 @@ public abstract class AsyncInitializationActivity extends AppCompatActivity impl
return mWindowAndroid;
}
/**
* @return The {@link ModalDialogManager} created for this class.
*/
@Nullable
protected ModalDialogManager createModalDialogManager() {
return null;
}
/**
* @return The {@link ModalDialogManager} that manages the display of modal dialogs (e.g.
* JavaScript dialogs).
*/
public ModalDialogManager getModalDialogManager() {
return mModalDialogManager;
}
/**
* Overrides the originally created modal dialog manager.
*/
public void overrideModalDialogManager(ModalDialogManager modalDialogManager) {
mModalDialogManager = modalDialogManager;
}
/**
* This will handle passing {@link Intent} results back to the {@link WindowAndroid}. It will
* return whether or not the {@link WindowAndroid} has consumed the event or not.
......@@ -718,7 +749,7 @@ public abstract class AsyncInitializationActivity extends AppCompatActivity impl
/**
* @return {@link ActivityLifecycleDispatcher} associated with this activity.
*/
protected ActivityLifecycleDispatcher getLifecycleDispatcher() {
public ActivityLifecycleDispatcher getLifecycleDispatcher() {
return mLifecycleDispatcher;
}
......
......@@ -5,6 +5,8 @@
package org.chromium.chrome.browser.modaldialog;
import org.chromium.chrome.browser.ChromeActivity;
import org.chromium.chrome.browser.lifecycle.Destroyable;
import org.chromium.chrome.browser.lifecycle.NativeInitObserver;
import org.chromium.chrome.browser.modaldialog.ModalDialogManager.ModalDialogType;
import org.chromium.chrome.browser.tab.EmptyTabObserver;
import org.chromium.chrome.browser.tab.Tab;
......@@ -17,7 +19,7 @@ import org.chromium.chrome.browser.tabmodel.TabModelSelectorTabModelObserver;
* Class responsible for handling dismissal of a tab modal dialog on user actions outside the tab
* modal dialog.
*/
public class TabModalLifetimeHandler {
public class TabModalLifetimeHandler implements NativeInitObserver, Destroyable {
/** The observer to dismiss all dialogs when the attached tab is not interactable. */
private final TabObserver mTabObserver = new EmptyTabObserver() {
@Override
......@@ -35,11 +37,12 @@ public class TabModalLifetimeHandler {
}
};
private final ChromeActivity mActivity;
private final ModalDialogManager mManager;
private final TabModalPresenter mPresenter;
private final TabModelSelectorTabModelObserver mTabModelObserver;
private final boolean mHasBottomControls;
private TabModalPresenter mPresenter;
private TabModelSelectorTabModelObserver mTabModelObserver;
private boolean mHasBottomControls;
private Tab mActiveTab;
/**
......@@ -47,30 +50,9 @@ public class TabModalLifetimeHandler {
* @param manager The {@link ModalDialogManager} that this handler handles.
*/
public TabModalLifetimeHandler(ChromeActivity activity, ModalDialogManager manager) {
mActivity = activity;
mManager = manager;
mPresenter = new TabModalPresenter(activity);
mManager.registerPresenter(mPresenter, ModalDialogType.TAB);
mHasBottomControls = activity.getBottomSheet() != null;
TabModelSelector tabModelSelector = activity.getTabModelSelector();
mTabModelObserver = new TabModelSelectorTabModelObserver(tabModelSelector) {
@Override
public void didSelectTab(Tab tab, @TabModel.TabSelectionType int type, int lastId) {
// Do not use lastId here since it can be the selected tab's ID if model is switched
// inside tab switcher.
if (tab != mActiveTab) {
mManager.dismissDialogsOfType(
ModalDialogType.TAB, DialogDismissalCause.TAB_SWITCHED);
if (mActiveTab != null) mActiveTab.removeObserver(mTabObserver);
mActiveTab = tab;
if (mActiveTab != null) {
mActiveTab.addObserver(mTabObserver);
updateSuspensionState();
}
}
}
};
activity.getLifecycleDispatcher().register(this);
}
/**
......@@ -78,6 +60,8 @@ public class TabModalLifetimeHandler {
* @param hasFocus Whether the omnibox currently has focus.
*/
public void onOmniboxFocusChanged(boolean hasFocus) {
if (mPresenter == null) return;
// If has bottom controls, the view hierarchy will be updated by mBottomSheetObserver.
if (mPresenter.getModalDialog() != null && !mHasBottomControls) {
mPresenter.updateContainerHierarchy(!hasFocus);
......@@ -88,16 +72,45 @@ public class TabModalLifetimeHandler {
* Handle a back press event.
*/
public boolean handleBackPress() {
if (mPresenter.getModalDialog() == null) return false;
if (mPresenter == null || mPresenter.getModalDialog() == null) return false;
mPresenter.dismissCurrentDialog(DialogDismissalCause.NAVIGATE_BACK_OR_TOUCH_OUTSIDE);
return true;
}
/**
* Remove any remaining dependencies.
*/
@Override
public void onFinishNativeInitialization() {
mPresenter = new TabModalPresenter(mActivity);
mManager.registerPresenter(mPresenter, ModalDialogType.TAB);
mHasBottomControls = mActivity.getBottomSheet() != null;
handleTabChanged(mActivity.getActivityTab());
TabModelSelector tabModelSelector = mActivity.getTabModelSelector();
mTabModelObserver = new TabModelSelectorTabModelObserver(tabModelSelector) {
@Override
public void didSelectTab(Tab tab, @TabModel.TabSelectionType int type, int lastId) {
handleTabChanged(tab);
}
};
}
private void handleTabChanged(Tab tab) {
// Do not use lastId here since it can be the selected tab's ID if model is switched
// inside tab switcher.
if (tab != mActiveTab) {
mManager.dismissDialogsOfType(ModalDialogType.TAB, DialogDismissalCause.TAB_SWITCHED);
if (mActiveTab != null) mActiveTab.removeObserver(mTabObserver);
mActiveTab = tab;
if (mActiveTab != null) {
mActiveTab.addObserver(mTabObserver);
updateSuspensionState();
}
}
}
@Override
public void destroy() {
mTabModelObserver.destroy();
if (mTabModelObserver != null) mTabModelObserver.destroy();
}
/** Update whether the {@link ModalDialogManager} should suspend tab modal dialogs. */
......
......@@ -251,6 +251,7 @@ public class LocationBarLayout extends FrameLayout
mUrlCoordinator.setWindowDelegate(windowDelegate);
mStatusViewCoordinator.setWindowAndroid(windowAndroid);
mAutocompleteCoordinator.setWindowAndroid(windowAndroid);
}
/**
......
......@@ -29,6 +29,7 @@ import org.chromium.chrome.browser.profiles.Profile;
import org.chromium.chrome.browser.toolbar.ToolbarDataProvider;
import org.chromium.chrome.browser.util.KeyNavigationUtil;
import org.chromium.ui.base.PageTransition;
import org.chromium.ui.base.WindowAndroid;
import java.util.List;
......@@ -154,6 +155,13 @@ public class AutocompleteCoordinator implements UrlFocusChangeListener, UrlTextC
mMediator.setAutocompleteProfile(profile);
}
/**
* Set the WindowAndroid instance associated with the containing Activity.
*/
public void setWindowAndroid(WindowAndroid windowAndroid) {
mMediator.setWindowAndroid(windowAndroid);
}
/**
* Whether omnibox autocomplete should currently be prevented from generating suggestions.
*/
......
......@@ -4,13 +4,12 @@
package org.chromium.chrome.browser.omnibox.suggestions;
import android.app.Activity;
import android.content.Context;
import android.content.DialogInterface;
import android.graphics.Bitmap;
import android.os.Handler;
import android.os.SystemClock;
import android.support.annotation.Nullable;
import android.support.v7.app.AlertDialog;
import android.text.Spannable;
import android.text.SpannableString;
import android.text.TextUtils;
......@@ -18,7 +17,6 @@ import android.text.style.StyleSpan;
import android.util.Pair;
import android.util.TypedValue;
import android.view.View;
import android.view.WindowManager;
import android.widget.ListView;
import android.widget.TextView;
......@@ -27,6 +25,10 @@ import org.chromium.base.ThreadUtils;
import org.chromium.base.VisibleForTesting;
import org.chromium.base.metrics.RecordUserAction;
import org.chromium.chrome.R;
import org.chromium.chrome.browser.init.AsyncInitializationActivity;
import org.chromium.chrome.browser.modaldialog.DialogDismissalCause;
import org.chromium.chrome.browser.modaldialog.ModalDialogManager;
import org.chromium.chrome.browser.modaldialog.ModalDialogView;
import org.chromium.chrome.browser.modelutil.PropertyModel;
import org.chromium.chrome.browser.omnibox.LocationBarVoiceRecognitionHandler;
import org.chromium.chrome.browser.omnibox.MatchClassificationStyle;
......@@ -43,6 +45,7 @@ import org.chromium.chrome.browser.toolbar.ToolbarDataProvider;
import org.chromium.content_public.browser.WebContents;
import org.chromium.ui.base.DeviceFormFactor;
import org.chromium.ui.base.PageTransition;
import org.chromium.ui.base.WindowAndroid;
import java.util.ArrayList;
import java.util.HashMap;
......@@ -102,6 +105,9 @@ class AutocompleteMediator implements OnSuggestionsReceivedListener {
private float mMaxRequiredWidth;
private float mMaxMatchContentsWidth;
private WindowAndroid mWindowAndroid;
private ModalDialogView mSuggestionDeleteDialog;
public AutocompleteMediator(Context context, AutocompleteDelegate delegate,
UrlBarEditingTextStateProvider textProvider, PropertyModel listPropertyModel) {
mContext = context;
......@@ -422,6 +428,11 @@ class AutocompleteMediator implements OnSuggestionsReceivedListener {
mDataProvider = provider;
}
/** Set the WindowAndroid instance associated with the containing Activity. */
void setWindowAndroid(WindowAndroid window) {
mWindowAndroid = window;
}
/**
* Sets the layout direction to be used for any new suggestion views.
* @see View#setLayoutDirection(int)
......@@ -644,30 +655,46 @@ class AutocompleteMediator implements OnSuggestionsReceivedListener {
RecordUserAction.record("MobileOmniboxDeleteGesture");
if (!suggestion.isDeletable()) return;
// TODO(tedchoc): Migrate to modal dialog manager.
AlertDialog.Builder b = new AlertDialog.Builder(mContext, R.style.AlertDialogTheme);
b.setTitle(suggestion.getDisplayText());
b.setMessage(R.string.omnibox_confirm_delete);
if (mWindowAndroid == null) return;
Activity activity = mWindowAndroid.getActivity().get();
if (activity == null || !(activity instanceof AsyncInitializationActivity)) return;
ModalDialogManager manager =
((AsyncInitializationActivity) activity).getModalDialogManager();
if (manager == null) {
assert false : "No modal dialog manager registered for this activity.";
return;
}
ModalDialogView.Params dialogParams = new ModalDialogView.Params();
dialogParams.title = suggestion.getDisplayText();
dialogParams.message = mContext.getString(R.string.omnibox_confirm_delete);
dialogParams.positiveButtonTextId = R.string.ok;
dialogParams.negativeButtonTextId = R.string.cancel;
DialogInterface.OnClickListener clickListener = new DialogInterface.OnClickListener() {
ModalDialogView.Controller dialogController = new ModalDialogView.Controller() {
@Override
public void onClick(DialogInterface dialog, int which) {
if (which == DialogInterface.BUTTON_POSITIVE) {
public void onDismiss(int dismissalCause) {
mSuggestionDeleteDialog = null;
}
@Override
public void onClick(int buttonType) {
if (buttonType == ModalDialogView.ButtonType.POSITIVE) {
RecordUserAction.record("MobileOmniboxDeleteRequested");
mAutocomplete.deleteSuggestion(position, suggestion.hashCode());
} else if (which == DialogInterface.BUTTON_NEGATIVE) {
dialog.cancel();
manager.dismissDialog(
mSuggestionDeleteDialog, DialogDismissalCause.POSITIVE_BUTTON_CLICKED);
} else if (buttonType == ModalDialogView.ButtonType.NEGATIVE) {
manager.dismissDialog(
mSuggestionDeleteDialog, DialogDismissalCause.NEGATIVE_BUTTON_CLICKED);
}
}
};
b.setPositiveButton(android.R.string.ok, clickListener);
b.setNegativeButton(android.R.string.cancel, clickListener);
AlertDialog dialog = b.create();
try {
dialog.show();
} catch (WindowManager.BadTokenException ex) {
}
mSuggestionDeleteDialog = new ModalDialogView(dialogController, dialogParams);
// Prevent updates to the shown omnibox suggestions list while the dialog is open.
stopAutocomplete(false);
manager.showDialog(mSuggestionDeleteDialog, ModalDialogManager.ModalDialogType.APP);
}
/**
......
......@@ -27,6 +27,8 @@ import org.chromium.chrome.browser.document.ChromeLauncherActivity;
import org.chromium.chrome.browser.init.AsyncInitializationActivity;
import org.chromium.chrome.browser.init.SingleWindowKeyboardVisibilityDelegate;
import org.chromium.chrome.browser.locale.LocaleManager;
import org.chromium.chrome.browser.modaldialog.AppModalPresenter;
import org.chromium.chrome.browser.modaldialog.ModalDialogManager;
import org.chromium.chrome.browser.omnibox.suggestions.AutocompleteController;
import org.chromium.chrome.browser.snackbar.SnackbarManager;
import org.chromium.chrome.browser.snackbar.SnackbarManager.SnackbarManageable;
......@@ -125,6 +127,12 @@ public class SearchActivity extends AsyncInitializationActivity
};
}
@Override
protected ModalDialogManager createModalDialogManager() {
return new ModalDialogManager(
new AppModalPresenter(this), ModalDialogManager.ModalDialogType.APP);
}
@Override
protected void triggerLayoutInflation() {
mSnackbarManager = new SnackbarManager(this, null);
......
......@@ -343,7 +343,7 @@ public class VrShell extends GvrLayout
mVrModalPresenter = new VrModalPresenter(this);
mVrModalDialogManager =
new ModalDialogManager(mVrModalPresenter, ModalDialogManager.ModalDialogType.APP);
mActivity.setModalDialogManager(mVrModalDialogManager);
mActivity.overrideModalDialogManager(mVrModalDialogManager);
ViewGroup decor = (ViewGroup) mActivity.getWindow().getDecorView();
mUiView = new FrameLayout(decor.getContext());
......@@ -747,7 +747,7 @@ public class VrShell extends GvrLayout
if (mVrBrowsingEnabled) {
if (mVrModalDialogManager != null) {
mVrModalDialogManager.dismissAllDialogs(DialogDismissalCause.UNKNOWN);
mActivity.setModalDialogManager(mNonVrModalDialogManager);
mActivity.overrideModalDialogManager(mNonVrModalDialogManager);
mVrModalDialogManager = null;
}
mNonVrViews.destroy();
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment