Commit 2cd71158 authored by Sky Malice's avatar Sky Malice Committed by Commit Bot

[Touchless] Open last tab only shows from touchless activity.

Bug: 976829
Change-Id: If287af7835e5d17fc0e9f16bbc4f99a104e5f36e
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1681401
Commit-Queue: Sky Malice <skym@chromium.org>
Reviewed-by: default avatarMichael Thiessen <mthiesse@chromium.org>
Reviewed-by: default avatarPavel Yatsuk <pavely@chromium.org>
Cr-Commit-Position: refs/heads/master@{#673388}
parent 22b27559
...@@ -7,21 +7,20 @@ package org.chromium.chrome.browser.touchless; ...@@ -7,21 +7,20 @@ package org.chromium.chrome.browser.touchless;
import static android.text.format.DateUtils.MINUTE_IN_MILLIS; import static android.text.format.DateUtils.MINUTE_IN_MILLIS;
import static android.text.format.DateUtils.getRelativeTimeSpanString; import static android.text.format.DateUtils.getRelativeTimeSpanString;
import android.app.Activity;
import android.content.Context; import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences; import android.content.SharedPreferences;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.graphics.Bitmap; import android.graphics.Bitmap;
import android.net.Uri;
import org.chromium.base.task.PostTask; import org.chromium.base.task.PostTask;
import org.chromium.base.task.TaskTraits; import org.chromium.base.task.TaskTraits;
import org.chromium.chrome.browser.ActivityTabProvider;
import org.chromium.chrome.browser.favicon.LargeIconBridge; import org.chromium.chrome.browser.favicon.LargeIconBridge;
import org.chromium.chrome.browser.history.BrowsingHistoryBridge; import org.chromium.chrome.browser.history.BrowsingHistoryBridge;
import org.chromium.chrome.browser.history.HistoryItem; import org.chromium.chrome.browser.history.HistoryItem;
import org.chromium.chrome.browser.history.HistoryProvider; import org.chromium.chrome.browser.history.HistoryProvider;
import org.chromium.chrome.browser.native_page.ContextMenuManager; import org.chromium.chrome.browser.native_page.ContextMenuManager;
import org.chromium.chrome.browser.native_page.NativePageFactory;
import org.chromium.chrome.browser.native_page.NativePageHost; import org.chromium.chrome.browser.native_page.NativePageHost;
import org.chromium.chrome.browser.profiles.Profile; import org.chromium.chrome.browser.profiles.Profile;
import org.chromium.chrome.browser.tab.EmptyTabObserver; import org.chromium.chrome.browser.tab.EmptyTabObserver;
...@@ -32,6 +31,7 @@ import org.chromium.chrome.browser.util.ViewUtils; ...@@ -32,6 +31,7 @@ import org.chromium.chrome.browser.util.ViewUtils;
import org.chromium.chrome.browser.widget.RoundedIconGenerator; import org.chromium.chrome.browser.widget.RoundedIconGenerator;
import org.chromium.chrome.touchless.R; import org.chromium.chrome.touchless.R;
import org.chromium.content_public.browser.LoadUrlParams; import org.chromium.content_public.browser.LoadUrlParams;
import org.chromium.content_public.browser.NavigationHandle;
import org.chromium.content_public.browser.UiThreadTaskTraits; import org.chromium.content_public.browser.UiThreadTaskTraits;
import org.chromium.ui.base.PageTransition; import org.chromium.ui.base.PageTransition;
import org.chromium.ui.modelutil.PropertyModel; import org.chromium.ui.modelutil.PropertyModel;
...@@ -44,10 +44,7 @@ import java.util.List; ...@@ -44,10 +44,7 @@ import java.util.List;
// TODO(crbug.com/948858): Add unit tests for this behavior. // TODO(crbug.com/948858): Add unit tests for this behavior.
class OpenLastTabMediator extends EmptyTabObserver class OpenLastTabMediator extends EmptyTabObserver
implements HistoryProvider.BrowsingHistoryObserver, FocusableComponent { implements HistoryProvider.BrowsingHistoryObserver, FocusableComponent {
private static final String LAST_REMOVED_VISIT_TIMESTAMP_KEY = private static final String LAST_TAB_URL = "TOUCHLESS_LAST_TAB_URL";
"TOUCHLESS_LAST_REMOVED_VISIT_TIMESTAMP";
// Used to match URLs in Chome's history to PWA launches via webapk.
private static final String WEBAPK_CLASS_NAME = "org.chromium.webapk.shell_apk";
private final Context mContext; private final Context mContext;
private final Profile mProfile; private final Profile mProfile;
...@@ -60,8 +57,34 @@ class OpenLastTabMediator extends EmptyTabObserver ...@@ -60,8 +57,34 @@ class OpenLastTabMediator extends EmptyTabObserver
private final LargeIconBridge mIconBridge; private final LargeIconBridge mIconBridge;
private HistoryItem mHistoryItem; private HistoryItem mHistoryItem;
private List<HistoryItem> mHistoryResult;
private boolean mPreferencesRead; private boolean mPreferencesRead;
private long mLastRemovedVisitTimestamp = Long.MIN_VALUE; private String mLastTabUrl;
/**
* Sets up an observer on the tab to track the last tab that was opened. The purpose of this is
* to filter out history results that come from other activities, like PWAs.
* @param activity the activity to lookup shared prefs with.
* @param activityTabProvider the source of the tab navigation events.
* @return a new observer that can be destroyed on shutdown.
*/
public static ActivityTabProvider.ActivityTabTabObserver createActivityScopedObserver(
Activity activity, ActivityTabProvider activityTabProvider) {
return new ActivityTabProvider.ActivityTabTabObserver(activityTabProvider) {
@Override
public void onDidFinishNavigation(Tab tab, NavigationHandle navigation) {
String url = tab.getUrl();
if (navigation.isInMainFrame() && !NativePageFactory.isNativePageUrl(url, false)) {
PostTask.postTask(TaskTraits.USER_VISIBLE, () -> {
SharedPreferences prefs = getSharedPreferences(activity);
prefs.edit()
.putString(OpenLastTabMediator.LAST_TAB_URL, tab.getUrl())
.apply();
});
}
}
};
}
OpenLastTabMediator(Context context, Profile profile, NativePageHost nativePageHost, OpenLastTabMediator(Context context, Profile profile, NativePageHost nativePageHost,
PropertyModel model, OpenLastTabView view) { PropertyModel model, OpenLastTabView view) {
...@@ -86,15 +109,18 @@ class OpenLastTabMediator extends EmptyTabObserver ...@@ -86,15 +109,18 @@ class OpenLastTabMediator extends EmptyTabObserver
} }
private SharedPreferences getSharedPreferences() { private SharedPreferences getSharedPreferences() {
return mNativePageHost.getActiveTab().getActivity().getPreferences(Context.MODE_PRIVATE); return getSharedPreferences(mNativePageHost.getActiveTab().getActivity());
}
private static SharedPreferences getSharedPreferences(Activity activity) {
return activity.getPreferences(Context.MODE_PRIVATE);
} }
private void readPreferences() { private void readPreferences() {
PostTask.postTask(TaskTraits.USER_VISIBLE, () -> { PostTask.postTask(TaskTraits.USER_VISIBLE, () -> {
// Check if this is a first launch of Chrome. // Check if this is a first launch of Chrome.
SharedPreferences prefs = getSharedPreferences(); SharedPreferences prefs = getSharedPreferences();
mLastRemovedVisitTimestamp = mLastTabUrl = prefs.getString(LAST_TAB_URL, null);
prefs.getLong(LAST_REMOVED_VISIT_TIMESTAMP_KEY, Long.MIN_VALUE);
PostTask.postTask(UiThreadTaskTraits.USER_VISIBLE, () -> { PostTask.postTask(UiThreadTaskTraits.USER_VISIBLE, () -> {
mPreferencesRead = true; mPreferencesRead = true;
updateModel(); updateModel();
...@@ -134,23 +160,10 @@ class OpenLastTabMediator extends EmptyTabObserver ...@@ -134,23 +160,10 @@ class OpenLastTabMediator extends EmptyTabObserver
@Override @Override
public void onQueryHistoryComplete(List<HistoryItem> items, boolean hasMorePotentialMatches) { public void onQueryHistoryComplete(List<HistoryItem> items, boolean hasMorePotentialMatches) {
mHistoryItem = null; mHistoryItem = null;
if (items.size() > 0) { mHistoryResult = items;
for (int i = 0; i < items.size(); i++) { // Ignore |hasMorePotentialMatches|, it's possible a user with a lot of PWA history does
HistoryItem currentItem = items.get(i); // not get a match in the first query. In this case, we'll simply not show the last tab
// Filter for history items that correspond to PWAs launched through webapk. // button. It probably isn't really recent anyways.
if (historyItemMatchesWebApkIntent(currentItem)) {
continue;
} else {
mHistoryItem = currentItem;
break;
}
}
if (mHistoryItem == null && hasMorePotentialMatches) {
mHistoryBridge.queryHistoryContinuation();
return;
}
}
if (mPreferencesRead) { if (mPreferencesRead) {
updateModel(); updateModel();
...@@ -160,7 +173,17 @@ class OpenLastTabMediator extends EmptyTabObserver ...@@ -160,7 +173,17 @@ class OpenLastTabMediator extends EmptyTabObserver
// updateModel is only called after preferences are read. It populates model with data from // updateModel is only called after preferences are read. It populates model with data from
// mHistoryItem. // mHistoryItem.
private void updateModel() { private void updateModel() {
if (mHistoryItem == null || mHistoryItem.getTimestamp() <= mLastRemovedVisitTimestamp) { if (mHistoryResult != null) {
for (HistoryItem item : mHistoryResult) {
if (item.getUrl().equals(mLastTabUrl)) {
mHistoryItem = item;
break;
}
}
mHistoryResult = null;
}
if (mHistoryItem == null) {
// Consider the case where the history has nothing in it to be a failure. // Consider the case where the history has nothing in it to be a failure.
mModel.set(OpenLastTabProperties.OPEN_LAST_TAB_LOAD_SUCCESS, false); mModel.set(OpenLastTabProperties.OPEN_LAST_TAB_LOAD_SUCCESS, false);
return; return;
...@@ -223,16 +246,15 @@ class OpenLastTabMediator extends EmptyTabObserver ...@@ -223,16 +246,15 @@ class OpenLastTabMediator extends EmptyTabObserver
@Override @Override
public void removeItem() { public void removeItem() {
mLastRemovedVisitTimestamp = mHistoryItem.getTimestamp();
PostTask.postTask(TaskTraits.USER_VISIBLE, () -> { PostTask.postTask(TaskTraits.USER_VISIBLE, () -> {
SharedPreferences prefs = getSharedPreferences(); SharedPreferences prefs = getSharedPreferences();
prefs.edit() prefs.edit().remove(LAST_TAB_URL).apply();
.putLong(LAST_REMOVED_VISIT_TIMESTAMP_KEY,
mLastRemovedVisitTimestamp)
.apply();
}); });
mHistoryBridge.markItemForRemoval(mHistoryItem); mHistoryBridge.markItemForRemoval(mHistoryItem);
mHistoryBridge.removeItems(); mHistoryBridge.removeItems();
mHistoryItem = null;
mLastTabUrl = null;
updateModel();
} }
@Override @Override
...@@ -257,30 +279,4 @@ class OpenLastTabMediator extends EmptyTabObserver ...@@ -257,30 +279,4 @@ class OpenLastTabMediator extends EmptyTabObserver
}; };
mModel.set(OpenLastTabProperties.CONTEXT_MENU_DELEGATE, delegate); mModel.set(OpenLastTabProperties.CONTEXT_MENU_DELEGATE, delegate);
} }
/**
* @param item The HistoryItem to check.
* @return True if the HistoryItem corresponds to a PWA launched through webapk.
*/
private boolean historyItemMatchesWebApkIntent(HistoryItem item) {
Uri uri = Uri.parse(item.getUrl());
Intent intent = new Intent(Intent.ACTION_VIEW, uri);
List<ResolveInfo> resolveInfo = mContext.getPackageManager().queryIntentActivities(
intent, PackageManager.MATCH_ALL);
if (resolveInfo == null || resolveInfo.isEmpty()) {
return false;
}
for (ResolveInfo info : resolveInfo) {
if (info.activityInfo == null) {
continue;
}
if (info.activityInfo.name.contains(WEBAPK_CLASS_NAME)) {
return true;
}
}
return false;
}
} }
...@@ -9,6 +9,7 @@ import android.view.KeyEvent; ...@@ -9,6 +9,7 @@ import android.view.KeyEvent;
import android.view.ViewGroup; import android.view.ViewGroup;
import org.chromium.chrome.R; import org.chromium.chrome.R;
import org.chromium.chrome.browser.ActivityTabProvider;
import org.chromium.chrome.browser.AppHooks; import org.chromium.chrome.browser.AppHooks;
import org.chromium.chrome.browser.ChromeActivity; import org.chromium.chrome.browser.ChromeActivity;
import org.chromium.chrome.browser.lifecycle.Destroyable; import org.chromium.chrome.browser.lifecycle.Destroyable;
...@@ -41,6 +42,8 @@ public class TouchlessUiCoordinatorImpl implements Destroyable, NativeInitObserv ...@@ -41,6 +42,8 @@ public class TouchlessUiCoordinatorImpl implements Destroyable, NativeInitObserv
private TooltipView mTooltipView; private TooltipView mTooltipView;
private ProgressBarView mProgressBarView; private ProgressBarView mProgressBarView;
private ActivityTabProvider.ActivityTabTabObserver mOpenLastTabObserver;
/** The class that enables zooming for all websites and handles touchless zooming. */ /** The class that enables zooming for all websites and handles touchless zooming. */
private TouchlessZoomHelper mTouchlessZoomHelper; private TouchlessZoomHelper mTouchlessZoomHelper;
...@@ -65,6 +68,9 @@ public class TouchlessUiCoordinatorImpl implements Destroyable, NativeInitObserv ...@@ -65,6 +68,9 @@ public class TouchlessUiCoordinatorImpl implements Destroyable, NativeInitObserv
mProgressBarCoordinator = mProgressBarCoordinator =
new ProgressBarCoordinator(mProgressBarView, mActivity.getActivityTabProvider()); new ProgressBarCoordinator(mProgressBarView, mActivity.getActivityTabProvider());
mOpenLastTabObserver = OpenLastTabMediator.createActivityScopedObserver(
mActivity, mActivity.getActivityTabProvider());
} }
@Override @Override
...@@ -126,5 +132,6 @@ public class TouchlessUiCoordinatorImpl implements Destroyable, NativeInitObserv ...@@ -126,5 +132,6 @@ public class TouchlessUiCoordinatorImpl implements Destroyable, NativeInitObserv
if (mKeyFunctionsIPHCoordinator != null) mKeyFunctionsIPHCoordinator.destroy(); if (mKeyFunctionsIPHCoordinator != null) mKeyFunctionsIPHCoordinator.destroy();
if (mTouchlessZoomHelper != null) mTouchlessZoomHelper.destroy(); if (mTouchlessZoomHelper != null) mTouchlessZoomHelper.destroy();
if (mProgressBarCoordinator != null) mProgressBarCoordinator.destroy(); if (mProgressBarCoordinator != null) mProgressBarCoordinator.destroy();
if (mOpenLastTabObserver != null) mOpenLastTabObserver.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