blob: 950987b7bb188ae6e1c3cffdd56595da3a58a99b [file] [log] [blame]
// Copyright 2013 The Chromium Authors
// 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.recent_tabs;
import androidx.annotation.VisibleForTesting;
import org.chromium.base.CollectionUtil;
import org.chromium.base.annotations.CalledByNative;
import org.chromium.base.annotations.NativeMethods;
import org.chromium.chrome.browser.profiles.Profile;
import org.chromium.chrome.browser.tab.Tab;
import org.chromium.chrome.browser.tab.TabLaunchType;
import org.chromium.chrome.browser.tabmodel.TabCreatorManager;
import org.chromium.components.sync_device_info.FormFactor;
import org.chromium.content_public.browser.LoadUrlParams;
import org.chromium.content_public.common.ContentUrlConstants;
import org.chromium.url.GURL;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
/**
* This class exposes to Java information about sessions, windows, and tabs on the user's synced
* devices.
*/
public class ForeignSessionHelper {
private long mNativeForeignSessionHelper;
/**
* Callback interface for getting notified when foreign session sync is updated.
*/
public interface ForeignSessionCallback {
/**
* This method will be called every time foreign session sync is updated.
*
* It's a good place to call {@link ForeignSessionHelper#getForeignSessions()} to get the
* updated information.
*/
@CalledByNative("ForeignSessionCallback")
void onUpdated();
}
/**
* Represents synced foreign session.
* Form factor value correlations can be found in the components/sync_device_info/device_info.h
* file or its Java generated counterpart.
*/
public static class ForeignSession {
public final String tag;
public final String name;
public final long modifiedTime;
public final List<ForeignSessionWindow> windows = new ArrayList<ForeignSessionWindow>();
public final @FormFactor int formFactor;
private ForeignSession(
String tag, String name, long modifiedTime, @FormFactor int formFactor) {
this(tag, name, modifiedTime, new ArrayList<>(), formFactor);
}
@VisibleForTesting
public ForeignSession(String tag, String name, long modifiedTime,
List<ForeignSessionWindow> windows, @FormFactor int formFactor) {
this.tag = tag;
this.name = name;
this.modifiedTime = modifiedTime;
this.windows.addAll(windows);
this.formFactor = formFactor;
}
}
/**
* Represents synced foreign window. Note that desktop Chrome can have multiple windows in a
* session.
*/
public static class ForeignSessionWindow {
public final long timestamp;
public final int sessionId;
public final List<ForeignSessionTab> tabs = new ArrayList<ForeignSessionTab>();
private ForeignSessionWindow(long timestamp, int sessionId) {
this(timestamp, sessionId, new ArrayList<>());
}
@VisibleForTesting
public ForeignSessionWindow(long timestamp, int sessionId, List<ForeignSessionTab> tabs) {
this.timestamp = timestamp;
this.sessionId = sessionId;
this.tabs.addAll(tabs);
}
}
/**
* Represents synced foreign tab.
*/
public static class ForeignSessionTab {
public final GURL url;
public final String title;
public final long timestamp;
public final int id;
@VisibleForTesting
public ForeignSessionTab(GURL url, String title, long timestamp, int id) {
this.url = url;
this.title = title;
this.timestamp = timestamp;
this.id = id;
}
}
@CalledByNative
private static ForeignSession pushSession(List<ForeignSession> sessions, String tag,
String name, long modifiedTime, @FormFactor int formFactor) {
ForeignSession session = new ForeignSession(tag, name, modifiedTime, formFactor);
sessions.add(session);
return session;
}
@CalledByNative
private static ForeignSessionWindow pushWindow(
ForeignSession session, long timestamp, int sessionId) {
ForeignSessionWindow window = new ForeignSessionWindow(timestamp, sessionId);
session.windows.add(window);
return window;
}
@CalledByNative
private static void pushTab(
ForeignSessionWindow window, GURL url, String title, long timestamp, int sessionId) {
ForeignSessionTab tab = new ForeignSessionTab(url, title, timestamp, sessionId);
window.tabs.add(tab);
}
/**
* Initialize this class with the given profile.
* @param profile Profile that will be used for syncing.
*/
public ForeignSessionHelper(Profile profile) {
mNativeForeignSessionHelper = ForeignSessionHelperJni.get().init(profile);
}
/**
* Clean up the C++ side of this class. After the call, this class instance shouldn't be used.
*/
public void destroy() {
assert mNativeForeignSessionHelper != 0;
ForeignSessionHelperJni.get().destroy(mNativeForeignSessionHelper);
mNativeForeignSessionHelper = 0;
}
/**
* @return {@code True} iff Tab sync is enabled.
*/
public boolean isTabSyncEnabled() {
return ForeignSessionHelperJni.get().isTabSyncEnabled(mNativeForeignSessionHelper);
}
/**
* Force a sync for sessions.
*/
public void triggerSessionSync() {
ForeignSessionHelperJni.get().triggerSessionSync(mNativeForeignSessionHelper);
}
/**
* Sets callback instance that will be called on every foreign session sync update.
* @param callback The callback to be invoked.
*/
public void setOnForeignSessionCallback(ForeignSessionCallback callback) {
ForeignSessionHelperJni.get().setOnForeignSessionCallback(
mNativeForeignSessionHelper, callback);
}
/**
* @return The list of synced foreign sessions. If it fails to get them for some reason will
* return an empty list.
*/
public List<ForeignSession> getForeignSessions() {
if (!isTabSyncEnabled()) {
return Collections.emptyList();
}
List<ForeignSession> result = new ArrayList<ForeignSession>();
boolean received = ForeignSessionHelperJni.get().getForeignSessions(
mNativeForeignSessionHelper, result);
if (!received) {
result = Collections.emptyList();
}
return result;
}
/**
* @return The list of synced foreign sessions that are from a mobile or tablet device. If it
* fails to get them for some reason will return an empty list.
*/
public List<ForeignSession> getMobileAndTabletForeignSessions() {
if (!isTabSyncEnabled()) {
return Collections.emptyList();
}
List<ForeignSession> result = new ArrayList<ForeignSession>();
boolean received = ForeignSessionHelperJni.get().getMobileAndTabletForeignSessions(
mNativeForeignSessionHelper, result);
if (!received) {
result = Collections.emptyList();
}
return result;
}
/**
* Opens the given foreign tab in a new tab.
* @param tab Tab to load the session into.
* @param session Session that the target tab belongs to.
* @param foreignTab Target tab to open.
* @param windowOpenDisposition The WindowOpenDisposition flag.
* @return {@code True} iff the tab is successfully opened.
*/
public boolean openForeignSessionTab(Tab tab, ForeignSession session,
ForeignSessionTab foreignTab, int windowOpenDisposition) {
return ForeignSessionHelperJni.get().openForeignSessionTab(mNativeForeignSessionHelper, tab,
session.tag, foreignTab.id, windowOpenDisposition);
}
/**
* Remove Foreign session to display. Note that it will be reappear on the next sync.
*
* This is mainly for when user wants to delete very old session that won't be used or syned in
* the future.
* @param session Session to be deleted.
*/
public void deleteForeignSession(ForeignSession session) {
ForeignSessionHelperJni.get().deleteForeignSession(
mNativeForeignSessionHelper, session.tag);
}
/**
* Enable invalidations for sessions sync related datatypes.
*/
public void setInvalidationsForSessionsEnabled(boolean enabled) {
ForeignSessionHelperJni.get().setInvalidationsForSessionsEnabled(
mNativeForeignSessionHelper, enabled);
}
/**
* Lazily instantiate a list of tabs as background tabs.
* @param sessionTabs List of target tabs to open.
* @param session Foreign session that holds the list of target tabs to open.
* @param tabCreatorManager Tab creator manager to create a new foreground tab for tab restore.
* @return The number of tabs that were successfully restored.
*/
public int openForeignSessionTabsAsBackgroundTabs(List<ForeignSessionTab> sessionTabs,
ForeignSession session, TabCreatorManager tabCreatorManager) {
List<Integer> tabIds = new ArrayList<>();
Tab newForegroundTab = tabCreatorManager.getTabCreator(false).createNewTab(
new LoadUrlParams(ContentUrlConstants.ABOUT_BLANK_URL),
TabLaunchType.FROM_RESTORE_TABS_UI, null);
for (ForeignSessionTab tab : sessionTabs) {
tabIds.add(tab.id);
}
if (tabIds.size() == 0) {
return 0;
}
return ForeignSessionHelperJni.get().openForeignSessionTabsAsBackgroundTabs(
mNativeForeignSessionHelper, newForegroundTab,
CollectionUtil.integerListToIntArray(tabIds), session.tag);
}
@NativeMethods
interface Natives {
long init(Profile profile);
void destroy(long nativeForeignSessionHelper);
boolean isTabSyncEnabled(long nativeForeignSessionHelper);
void triggerSessionSync(long nativeForeignSessionHelper);
void setOnForeignSessionCallback(
long nativeForeignSessionHelper, ForeignSessionCallback callback);
boolean getForeignSessions(
long nativeForeignSessionHelper, List<ForeignSession> resultSessions);
boolean getMobileAndTabletForeignSessions(
long nativeForeignSessionHelper, List<ForeignSession> resultSessions);
boolean openForeignSessionTab(long nativeForeignSessionHelper, Tab tab, String sessionTag,
int tabId, int disposition);
void deleteForeignSession(long nativeForeignSessionHelper, String sessionTag);
void setInvalidationsForSessionsEnabled(long nativeForeignSessionHelper, boolean enabled);
int openForeignSessionTabsAsBackgroundTabs(
long nativeForeignSessionHelper, Tab tab, int[] tabIds, String sessionTag);
}
}