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
5package org.chromium.chrome.browser;
6
7import org.chromium.base.CalledByNative;
8import org.chromium.chrome.browser.profiles.Profile;
9
10import java.util.ArrayList;
11import java.util.Collections;
12import java.util.Comparator;
13import 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 */
19public class ForeignSessionHelper {
20    private long 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        // Please keep in sync with synced_session.h
41        public static final int DEVICE_TYPE_UNSET = 0;
42        public static final int DEVICE_TYPE_WIN = 1;
43        public static final int DEVICE_TYPE_MACOSX = 2;
44        public static final int DEVICE_TYPE_LINUX = 3;
45        public static final int DEVICE_TYPE_CHROMEOS = 4;
46        public static final int DEVICE_TYPE_OTHER = 5;
47        public static final int DEVICE_TYPE_PHONE = 6;
48        public static final int DEVICE_TYPE_TABLET = 7;
49
50        public final String tag;
51        public final String name;
52        public final int deviceType;
53        public final long modifiedTime;
54        public final List<ForeignSessionWindow> windows = new ArrayList<ForeignSessionWindow>();
55
56        private ForeignSession(String tag, String name, int deviceType, long modifiedTime) {
57            this.tag = tag;
58            this.name = name;
59            this.deviceType = deviceType;
60            this.modifiedTime = modifiedTime;
61        }
62    }
63
64    /**
65     * Represents synced foreign window. Note that desktop Chrome can have multiple windows in a
66     * session.
67     */
68    public static class ForeignSessionWindow {
69        public final long timestamp;
70        public final int sessionId;
71        public final List<ForeignSessionTab> tabs = new ArrayList<ForeignSessionTab>();
72
73        private ForeignSessionWindow(long timestamp, int sessionId) {
74            this.timestamp = timestamp;
75            this.sessionId = sessionId;
76        }
77    }
78
79    /**
80     * Represents synced foreign tab.
81     */
82    public static class ForeignSessionTab {
83        public final String url;
84        public final String title;
85        public final long timestamp;
86        public final int id;
87
88        private ForeignSessionTab(String url, String title, long timestamp, int id) {
89            this.url = url;
90            this.title = title;
91            this.timestamp = timestamp;
92            this.id = id;
93        }
94    }
95
96    @CalledByNative
97    private static ForeignSession pushSession(
98            List<ForeignSession> sessions, String tag, String name, int deviceType,
99            long modifiedTime) {
100        ForeignSession session = new ForeignSession(tag, name, deviceType, modifiedTime);
101        sessions.add(session);
102        return session;
103    }
104
105    @CalledByNative
106    private static ForeignSessionWindow pushWindow(
107            ForeignSession session, long timestamp, int sessionId) {
108        ForeignSessionWindow window = new ForeignSessionWindow(timestamp, sessionId);
109        session.windows.add(window);
110        return window;
111    }
112
113    @CalledByNative
114    private static void pushTab(
115            ForeignSessionWindow window, String url, String title, long timestamp, int sessionId) {
116        ForeignSessionTab tab = new ForeignSessionTab(url, title, timestamp, sessionId);
117        window.tabs.add(tab);
118    }
119
120    /**
121     * Initialize this class with the given profile.
122     * @param profile Profile that will be used for syncing.
123     */
124    public ForeignSessionHelper(Profile profile) {
125        mNativeForeignSessionHelper = nativeInit(profile);
126    }
127
128    /**
129     * Clean up the C++ side of this class. After the call, this class instance shouldn't be used.
130     */
131    public void destroy() {
132        assert mNativeForeignSessionHelper != 0;
133        nativeDestroy(mNativeForeignSessionHelper);
134        mNativeForeignSessionHelper = 0;
135    }
136
137    @Override
138    protected void finalize() {
139        // Just to make sure that we called destroy() before the java garbage collection picks up.
140        assert mNativeForeignSessionHelper == 0;
141    }
142
143    /**
144     * @return {@code True} iff Tab sync is enabled.
145     */
146    public boolean isTabSyncEnabled() {
147        return nativeIsTabSyncEnabled(mNativeForeignSessionHelper);
148    }
149
150    /**
151     * Sets callback instance that will be called on every foreign session sync update.
152     * @param callback The callback to be invoked.
153     */
154    public void setOnForeignSessionCallback(ForeignSessionCallback callback) {
155        nativeSetOnForeignSessionCallback(mNativeForeignSessionHelper, callback);
156    }
157
158    /**
159     * @return The list of synced foreign sessions. {@code null} iff it fails to get them for some
160     *         reason.
161     */
162    public List<ForeignSession> getForeignSessions() {
163        List<ForeignSession> result = new ArrayList<ForeignSession>();
164        boolean received = nativeGetForeignSessions(mNativeForeignSessionHelper, result);
165        if (received) {
166            // Sort sessions from most recent to least recent.
167            Collections.sort(result, new Comparator<ForeignSession>() {
168                @Override
169                public int compare(ForeignSession lhs, ForeignSession rhs) {
170                    return lhs.modifiedTime < rhs.modifiedTime ? 1 :
171                        (lhs.modifiedTime == rhs.modifiedTime ? 0 : -1);
172                }
173            });
174        } else {
175            result = null;
176        }
177
178        return result;
179    }
180
181    /**
182     * Opens the given foreign tab in a new tab.
183     * @param tab Tab to load the session into.
184     * @param session Session that the target tab belongs to.
185     * @param foreignTab Target tab to open.
186     * @param windowOpenDisposition The WindowOpenDisposition flag.
187     * @return {@code True} iff the tab is successfully opened.
188     */
189    public boolean openForeignSessionTab(Tab tab, ForeignSession session,
190            ForeignSessionTab foreignTab, int windowOpenDisposition) {
191        return nativeOpenForeignSessionTab(mNativeForeignSessionHelper, tab, session.tag,
192                foreignTab.id, windowOpenDisposition);
193    }
194
195    /**
196     * Remove Foreign session to display. Note that it will be reappear on the next sync.
197     *
198     * This is mainly for when user wants to delete very old session that won't be used or syned in
199     * the future.
200     * @param session Session to be deleted.
201     */
202    public void deleteForeignSession(ForeignSession session) {
203        nativeDeleteForeignSession(mNativeForeignSessionHelper, session.tag);
204    }
205
206    private static native long nativeInit(Profile profile);
207    private static native void nativeDestroy(long nativeForeignSessionHelper);
208    private static native boolean nativeIsTabSyncEnabled(long nativeForeignSessionHelper);
209    private static native void nativeSetOnForeignSessionCallback(
210            long nativeForeignSessionHelper, ForeignSessionCallback callback);
211    private static native boolean nativeGetForeignSessions(long nativeForeignSessionHelper,
212            List<ForeignSession> resultSessions);
213    private static native boolean nativeOpenForeignSessionTab(
214            long nativeForeignSessionHelper, Tab tab, String sessionTag, int tabId,
215            int disposition);
216    private static native void nativeDeleteForeignSession(
217            long nativeForeignSessionHelper, String sessionTag);
218}
219