1 | // Copyright 2013 The Chromium Authors. All rights reserved. |
2 | // Use of this source code is governed by a BSD-style license that can be |
3 | // found in the LICENSE file. |
4 | |
5 | package org.chromium.chrome.browser; |
6 | |
7 | import org.chromium.base.CalledByNative; |
8 | import org.chromium.chrome.browser.profiles.Profile; |
9 | |
10 | import java.util.ArrayList; |
11 | import java.util.Collections; |
12 | import java.util.Comparator; |
13 | import java.util.List; |
14 | |
15 | /** |
16 | * This class exposes to Java information about sessions, windows, and tabs on the user's synced |
17 | * devices. |
18 | */ |
19 | public class ForeignSessionHelper { |
20 | private int mNativeForeignSessionHelper; |
21 | |
22 | /** |
23 | * Callback interface for getting notified when foreign session sync is updated. |
24 | */ |
25 | public interface ForeignSessionCallback { |
26 | /** |
27 | * This method will be called every time foreign session sync is updated. |
28 | * |
29 | * It's a good place to call {@link ForeignSessionHelper#getForeignSessions()} to get the |
30 | * updated information. |
31 | */ |
32 | @CalledByNative("ForeignSessionCallback") |
33 | public void onUpdated(); |
34 | } |
35 | |
36 | /** |
37 | * Represents synced foreign session. |
38 | */ |
39 | public static class ForeignSession { |
40 | public final String tag; |
41 | public final String name; |
42 | public final String deviceType; |
43 | public final long modifiedTime; |
44 | public final List<ForeignSessionWindow> windows = new ArrayList<ForeignSessionWindow>(); |
45 | |
46 | private ForeignSession(String tag, String name, String deviceType, long modifiedTime) { |
47 | this.tag = tag; |
48 | this.name = name; |
49 | this.deviceType = deviceType; |
50 | this.modifiedTime = modifiedTime; |
51 | } |
52 | } |
53 | |
54 | /** |
55 | * Represents synced foreign window. Note that desktop Chrome can have multiple windows in a |
56 | * session. |
57 | */ |
58 | public static class ForeignSessionWindow { |
59 | public final long timestamp; |
60 | public final int sessionId; |
61 | public final List<ForeignSessionTab> tabs = new ArrayList<ForeignSessionTab>(); |
62 | |
63 | private ForeignSessionWindow(long timestamp, int sessionId) { |
64 | this.timestamp = timestamp; |
65 | this.sessionId = sessionId; |
66 | } |
67 | } |
68 | |
69 | /** |
70 | * Represents synced foreign tab. |
71 | */ |
72 | public static class ForeignSessionTab { |
73 | public final String url; |
74 | public final String title; |
75 | public final long timestamp; |
76 | public final int id; |
77 | |
78 | private ForeignSessionTab(String url, String title, long timestamp, int id) { |
79 | this.url = url; |
80 | this.title = title; |
81 | this.timestamp = timestamp; |
82 | this.id = id; |
83 | } |
84 | } |
85 | |
86 | @CalledByNative |
87 | private static ForeignSession pushSession( |
88 | List<ForeignSession> sessions, String tag, String name, String deviceType, |
89 | long modifiedTime) { |
90 | ForeignSession session = new ForeignSession(tag, name, deviceType, modifiedTime); |
91 | sessions.add(session); |
92 | return session; |
93 | } |
94 | |
95 | @CalledByNative |
96 | private static ForeignSessionWindow pushWindow( |
97 | ForeignSession session, long timestamp, int sessionId) { |
98 | ForeignSessionWindow window = new ForeignSessionWindow(timestamp, sessionId); |
99 | session.windows.add(window); |
100 | return window; |
101 | } |
102 | |
103 | @CalledByNative |
104 | private static void pushTab( |
105 | ForeignSessionWindow window, String url, String title, long timestamp, int sessionId) { |
106 | ForeignSessionTab tab = new ForeignSessionTab(url, title, timestamp, sessionId); |
107 | window.tabs.add(tab); |
108 | } |
109 | |
110 | /** |
111 | * Initialize this class with the given profile. |
112 | * @param profile Profile that will be used for syncing. |
113 | */ |
114 | public ForeignSessionHelper(Profile profile) { |
115 | mNativeForeignSessionHelper = nativeInit(profile); |
116 | } |
117 | |
118 | /** |
119 | * Clean up the C++ side of this class. After the call, this class instance shouldn't be used. |
120 | */ |
121 | public void destroy() { |
122 | assert mNativeForeignSessionHelper != 0; |
123 | nativeDestroy(mNativeForeignSessionHelper); |
124 | } |
125 | |
126 | @Override |
127 | protected void finalize() { |
128 | // Just to make sure that we called destroy() before the java garbage collection picks up. |
129 | assert mNativeForeignSessionHelper == 0; |
130 | } |
131 | |
132 | /** |
133 | * @return {@code True} iff Tab sync is enabled. |
134 | */ |
135 | public boolean isTabSyncEnabled() { |
136 | return nativeIsTabSyncEnabled(mNativeForeignSessionHelper); |
137 | } |
138 | |
139 | /** |
140 | * Sets callback instance that will be called on every foreign session sync update. |
141 | */ |
142 | public void setOnForeignSessionCallback(ForeignSessionCallback callback) { |
143 | nativeSetOnForeignSessionCallback(mNativeForeignSessionHelper, callback); |
144 | } |
145 | |
146 | /** |
147 | * @return The list of synced foreign sessions. {@code null} iff it fails to get them for some |
148 | * reason. |
149 | */ |
150 | public List<ForeignSession> getForeignSessions() { |
151 | List<ForeignSession> result = new ArrayList<ForeignSession>(); |
152 | boolean received = nativeGetForeignSessions(mNativeForeignSessionHelper, result); |
153 | if (received) { |
154 | // Sort sessions from most recent to least recent. |
155 | Collections.sort(result, new Comparator<ForeignSession>() { |
156 | @Override |
157 | public int compare(ForeignSession lhs, ForeignSession rhs) { |
158 | return lhs.modifiedTime < rhs.modifiedTime ? 1 : |
159 | (lhs.modifiedTime == rhs.modifiedTime ? 0: -1); |
160 | } |
161 | }); |
162 | } else { |
163 | result = null; |
164 | } |
165 | |
166 | return result; |
167 | } |
168 | |
169 | /** |
170 | * Opens the given foreign tab in a new tab. |
171 | * @param session Session that the target tab belongs to. |
172 | * @param tab Target tab to open. |
173 | * @return {@code True} iff the tab is successfully opened. |
174 | */ |
175 | public boolean openForeignSessionTab(ForeignSession session, ForeignSessionTab tab) { |
176 | return nativeOpenForeignSessionTab(mNativeForeignSessionHelper, session.tag, tab.id); |
177 | } |
178 | |
179 | /** |
180 | * Set the given session collapsed or uncollapsed in preferences. |
181 | * @param session Session to set collapsed or uncollapsed. |
182 | * @param isCollapsed {@code True} iff we want the session to be collapsed. |
183 | */ |
184 | public void setForeignSessionCollapsed(ForeignSession session, boolean isCollapsed) { |
185 | nativeSetForeignSessionCollapsed(mNativeForeignSessionHelper, session.tag, isCollapsed); |
186 | } |
187 | |
188 | /** |
189 | * Remove Foreign session to display. Note that it will be reappear on the next sync. |
190 | * |
191 | * This is mainly for when user wants to delete very old session that won't be used or syned in |
192 | * the future. |
193 | * @param session Session to be deleted. |
194 | */ |
195 | public void deleteForeignSession(ForeignSession session) { |
196 | nativeDeleteForeignSession(mNativeForeignSessionHelper, session.tag); |
197 | } |
198 | |
199 | private static native int nativeInit(Profile profile); |
200 | private static native void nativeDestroy(int nativeForeignSessionHelper); |
201 | private static native boolean nativeIsTabSyncEnabled(int nativeForeignSessionHelper); |
202 | private static native void nativeSetOnForeignSessionCallback( |
203 | int nativeForeignSessionHelper, ForeignSessionCallback callback); |
204 | private static native boolean nativeGetForeignSessions(int nativeForeignSessionHelper, |
205 | List<ForeignSession> resultSessions); |
206 | private static native boolean nativeOpenForeignSessionTab( |
207 | int nativeForeignSessionHelper, String sessionTag, int tabId); |
208 | private static native void nativeSetForeignSessionCollapsed( |
209 | int nativeForeignSessionHelper, String sessionTag, boolean isCollapsed); |
210 | private static native void nativeDeleteForeignSession( |
211 | int nativeForeignSessionHelper, String sessionTag); |
212 | } |