15d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// Copyright 2014 The Chromium Authors. All rights reserved.
25d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
35d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// found in the LICENSE file.
45d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
55d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#ifndef GOOGLE_APIS_GAIA_MERGE_SESSION_HELPER_H_
65d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#define GOOGLE_APIS_GAIA_MERGE_SESSION_HELPER_H_
75d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
85d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include <deque>
95d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
105d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "base/observer_list.h"
116e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)#include "base/timer/timer.h"
125d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "google_apis/gaia/gaia_auth_consumer.h"
135d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "google_apis/gaia/ubertoken_fetcher.h"
14a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)#include "net/url_request/url_fetcher_delegate.h"
155d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
165d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)class GaiaAuthFetcher;
175d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)class GoogleServiceAuthError;
185d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)class OAuth2TokenService;
195d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
205d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)namespace net {
216e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)class URLFetcher;
225d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)class URLRequestContextGetter;
235d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
245d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
255d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// Merges a Google account known to Chrome into the cookie jar.  When merging
265d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// multiple accounts, one instance of the helper is better than multiple
275d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// instances if there is the possibility that they run concurrently, since
285d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// changes to the cookie must be serialized.
295d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)//
305d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// By default instances of MergeSessionHelper delete themselves when done.
315d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)class MergeSessionHelper : public GaiaAuthConsumer,
325d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                           public UbertokenConsumer,
335d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                           public net::URLFetcherDelegate {
345d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) public:
355d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  class Observer {
365d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)   public:
375d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    // Called whenever a merge session is completed.  The account that was
385d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    // merged is given by |account_id|.  If |error| is equal to
395d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    // GoogleServiceAuthError::AuthErrorNone() then the merge succeeeded.
405d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    virtual void MergeSessionCompleted(const std::string& account_id,
415d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                       const GoogleServiceAuthError& error) = 0;
425d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)   protected:
435d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    virtual ~Observer() {}
445d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  };
455d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
466e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  // Class to retrieve the external connection check results from gaia.
476e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  // Declared publicly for unit tests.
486e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  class ExternalCcResultFetcher : public GaiaAuthConsumer,
496e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)                                  public net::URLFetcherDelegate {
506e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)   public:
516e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    // Maps connection URLs, as returned by StartGetCheckConnectionInfo() to
526e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    // token and URLFetcher used to fetch the URL.
536e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    typedef std::map<GURL, std::pair<std::string, net::URLFetcher*> >
546e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)        URLToTokenAndFetcher;
556e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)
566e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    // Maps tokens to the fetched result for that token.
576e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    typedef std::map<std::string, std::string> ResultMap;
586e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)
596e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    ExternalCcResultFetcher(MergeSessionHelper* helper);
606e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    virtual ~ExternalCcResultFetcher();
616e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)
626e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    // Gets the current value of the external connection check result string.
636e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    std::string GetExternalCcResult();
646e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)
656e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    // Start fetching the external CC result.  If a fetch is already in progress
666e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    // it is canceled.
676e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    void Start();
686e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)
696e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    // Are external URLs still being checked?
706e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    bool IsRunning();
716e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)
726e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    // Returns a copy of the internal token to fetcher map.
736e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    URLToTokenAndFetcher get_fetcher_map_for_testing() {
746e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)      return fetchers_;
756e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    }
766e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)
776e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    // Simulate a timeout for tests.
786e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    void TimeoutForTests();
796e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)
806e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)   private:
816e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    // Overridden from GaiaAuthConsumer.
826e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    virtual void OnGetCheckConnectionInfoSuccess(
836e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)        const std::string& data) OVERRIDE;
846e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)
856e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    // Creates and initializes a URL fetcher for doing a connection check.
866e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    net::URLFetcher* CreateFetcher(const GURL& url);
876e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)
886e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    // Overridden from URLFetcherDelgate.
896e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    virtual void OnURLFetchComplete(const net::URLFetcher* source) OVERRIDE;
906e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)
916e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    // Any fetches still ongoing after this call are considered timed out.
926e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    void Timeout();
936e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)
946e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    void CleanupTransientState();
956e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)
966e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    MergeSessionHelper* helper_;
976e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    base::OneShotTimer<ExternalCcResultFetcher> timer_;
986e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    scoped_ptr<GaiaAuthFetcher> gaia_auth_fetcher_;
996e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    URLToTokenAndFetcher fetchers_;
1006e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    ResultMap results_;
1016e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)
1026e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    DISALLOW_COPY_AND_ASSIGN(ExternalCcResultFetcher);
1036e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  };
1046e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)
1055d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  MergeSessionHelper(OAuth2TokenService* token_service,
1065d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                     net::URLRequestContextGetter* request_context,
1075d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                     Observer* observer);
1085d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  virtual ~MergeSessionHelper();
1095d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1105d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  void LogIn(const std::string& account_id);
1115d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1125d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // Add or remove observers of this helper.
1135d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  void AddObserver(Observer* observer);
1145d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  void RemoveObserver(Observer* observer);
1155d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1165d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // Cancel all login requests.
1175d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  void CancelAll();
1185d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1195d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // Signout of |account_id| given a list of accounts already signed in.
1205d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // Since this involves signing out of all accounts and resigning back in,
1215d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // the order which |accounts| are given is important as it will dictate
1225d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // the sign in order. |account_id| does not have to be in |accounts|.
1235d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  void LogOut(const std::string& account_id,
1245d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)              const std::vector<std::string>& accounts);
1255d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1265d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // Signout all accounts.
1275d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  void LogOutAllAccounts();
1285d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
129010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  // Call observers when merge session completes.  This public so that callers
130010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  // that know that a given account is already in the cookie jar can simply
131010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  // inform the observers.
132010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  void SignalComplete(const std::string& account_id,
133010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)                      const GoogleServiceAuthError& error);
134010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)
135116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  // Returns true of there are pending log ins or outs.
136116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  bool is_running() const { return accounts_.size() > 0; }
137116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
1386e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  // Start the process of fetching the external check connection result so that
1396e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  // its ready when we try to perform a merge session.
1406e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  void StartFetchingExternalCcResult();
1416e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)
1426e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  // Returns true if the helper is still fetching external check connection
1436e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  // results.
1446e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  bool StillFetchingExternalCcResult();
1456e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)
1465d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) private:
1476e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  net::URLRequestContextGetter* request_context() { return request_context_; }
1486e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)
1495d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // Overridden from UbertokenConsumer.
1505d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  virtual void OnUbertokenSuccess(const std::string& token) OVERRIDE;
1515d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  virtual void OnUbertokenFailure(const GoogleServiceAuthError& error) OVERRIDE;
1525d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1535d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // Overridden from GaiaAuthConsumer.
1545d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  virtual void OnMergeSessionSuccess(const std::string& data) OVERRIDE;
1555d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  virtual void OnMergeSessionFailure(const GoogleServiceAuthError& error)
1565d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      OVERRIDE;
1575d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1585d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  void LogOutInternal(const std::string& account_id,
1595d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                      const std::vector<std::string>& accounts);
1605d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1615d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // Starts the proess of fetching the uber token and performing a merge session
1625d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // for the next account.  Virtual so that it can be overriden in tests.
1635d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  virtual void StartFetching();
1645d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1655d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // Virtual for testing purpose.
1665d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  virtual void StartLogOutUrlFetch();
1675d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1685d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // Start the next merge session, if needed.
1695d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  void HandleNextAccount();
1705d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1715d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // Overridden from URLFetcherDelgate.
1725d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  virtual void OnURLFetchComplete(const net::URLFetcher* source) OVERRIDE;
1735d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1745d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  OAuth2TokenService* token_service_;
1755d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  net::URLRequestContextGetter* request_context_;
1765d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  scoped_ptr<GaiaAuthFetcher> gaia_auth_fetcher_;
1775d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  scoped_ptr<UbertokenFetcher> uber_token_fetcher_;
1786e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  ExternalCcResultFetcher result_fetcher_;
1795d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1805d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // A worklist for this class. Accounts names are stored here if
1815d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // we are pending a signin action for that account. Empty strings
1825d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // represent a signout request.
1835d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  std::deque<std::string> accounts_;
1845d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1855d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // List of observers to notify when merge session completes.
1865d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // Makes sure list is empty on destruction.
1875d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  ObserverList<Observer, true> observer_list_;
1885d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1895d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  DISALLOW_COPY_AND_ASSIGN(MergeSessionHelper);
1905d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)};
1915d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1925d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#endif  // GOOGLE_APIS_GAIA_MERGE_SESSION_HELPER_H_
193