about_signin_internals.cc revision e5d81f57cb97b3b6b7fccc9c5610d21eb81db09d
12a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Copyright (c) 2012 The Chromium Authors. All rights reserved.
22a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
32a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// found in the LICENSE file.
42a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
5e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch#include "components/signin/core/browser/about_signin_internals.h"
62a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
72a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/debug/trace_event.h"
82a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/hash.h"
92a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/i18n/time_formatting.h"
102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/logging.h"
112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/prefs/pref_service.h"
125d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "base/strings/stringprintf.h"
13868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "base/strings/utf_string_conversions.h"
14effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch#include "components/signin/core/browser/profile_oauth2_token_service.h"
15e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch#include "components/signin/core/browser/signin_client.h"
16effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch#include "components/signin/core/browser/signin_internals_util.h"
17e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch#include "components/signin/core/browser/signin_manager.h"
182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "google_apis/gaia/gaia_constants.h"
192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
20c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)using base::Time;
212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)using namespace signin_internals_util;
222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
235d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)namespace {
245d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
255d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)std::string GetTimeStr(base::Time time) {
265d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  return base::UTF16ToUTF8(base::TimeFormatShortDateAndTime(time));
275d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
285d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
295d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)base::ListValue* AddSection(base::ListValue* parent_list,
305d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                            const std::string& title) {
315d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  scoped_ptr<base::DictionaryValue> section(new base::DictionaryValue());
325d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  base::ListValue* section_contents = new base::ListValue();
335d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
345d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  section->SetString("title", title);
355d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  section->Set("data", section_contents);
365d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  parent_list->Append(section.release());
375d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  return section_contents;
385d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
395d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
405d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void AddSectionEntry(base::ListValue* section_list,
415d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                     const std::string& field_name,
425d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                     const std::string& field_val) {
435d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  scoped_ptr<base::DictionaryValue> entry(new base::DictionaryValue());
445d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  entry->SetString("label", field_name);
455d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  entry->SetString("value", field_val);
465d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  section_list->Append(entry.release());
475d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
485d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
495d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)std::string SigninStatusFieldToLabel(UntimedSigninStatusField field) {
505d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  switch (field) {
515d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    case USERNAME:
525d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      return "User Id";
535d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    case UNTIMED_FIELDS_END:
545d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      NOTREACHED();
555d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      return std::string();
565d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
575d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  NOTREACHED();
585d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  return std::string();
595d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
605d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
61e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen MurdochTimedSigninStatusValue SigninStatusFieldToLabel(TimedSigninStatusField field) {
625d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  switch (field) {
635d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    case SIGNIN_TYPE:
645d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      return TimedSigninStatusValue("Type", "Time");
655d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    case CLIENT_LOGIN_STATUS:
665d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      return TimedSigninStatusValue("Last OnClientLogin Status",
675d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                    "Last OnClientLogin Time");
685d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    case OAUTH_LOGIN_STATUS:
695d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      return TimedSigninStatusValue("Last OnOAuthLogin Status",
705d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                    "Last OnOAuthLogin Time");
715d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
725d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    case GET_USER_INFO_STATUS:
735d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      return TimedSigninStatusValue("Last OnGetUserInfo Status",
745d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                    "Last OnGetUserInfo Time");
755d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    case UBER_TOKEN_STATUS:
765d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      return TimedSigninStatusValue("Last OnUberToken Status",
775d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                    "Last OnUberToken Time");
785d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    case MERGE_SESSION_STATUS:
795d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      return TimedSigninStatusValue("Last OnMergeSession Status",
805d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                    "Last OnMergeSession Time");
815d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    case TIMED_FIELDS_END:
825d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      NOTREACHED();
835d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      return TimedSigninStatusValue("Error", std::string());
845d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
855d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  NOTREACHED();
865d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  return TimedSigninStatusValue("Error", std::string());
875d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
885d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
895d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}  // anonymous namespace
905d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
91e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen MurdochAboutSigninInternals::AboutSigninInternals(
92e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch    ProfileOAuth2TokenService* token_service,
93e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch    SigninManagerBase* signin_manager)
94e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch    : token_service_(token_service),
95e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch      signin_manager_(signin_manager),
96e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch      client_(NULL) {}
972a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
98e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen MurdochAboutSigninInternals::~AboutSigninInternals() {}
992a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void AboutSigninInternals::AddSigninObserver(
1012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    AboutSigninInternals::Observer* observer) {
1022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  signin_observers_.AddObserver(observer);
1032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
1042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void AboutSigninInternals::RemoveSigninObserver(
1062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    AboutSigninInternals::Observer* observer) {
1072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  signin_observers_.RemoveObserver(observer);
1082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
1092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void AboutSigninInternals::NotifySigninValueChanged(
1112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const UntimedSigninStatusField& field,
1122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const std::string& value) {
1132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  unsigned int field_index = field - UNTIMED_FIELDS_BEGIN;
1142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(field_index >= 0 &&
1152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)         field_index < signin_status_.untimed_signin_fields.size());
1162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  signin_status_.untimed_signin_fields[field_index] = value;
1182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Also persist these values in the prefs.
1202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  const std::string pref_path = SigninStatusFieldToString(field);
121e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch  client_->GetPrefs()->SetString(pref_path.c_str(), value);
1222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  NotifyObservers();
1242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
1252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void AboutSigninInternals::NotifySigninValueChanged(
1272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const TimedSigninStatusField& field,
1282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const std::string& value) {
1292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  unsigned int field_index = field - TIMED_FIELDS_BEGIN;
1302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(field_index >= 0 &&
1312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)         field_index < signin_status_.timed_signin_fields.size());
1322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
133c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  Time now = Time::NowFromSystemTime();
1345d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  std::string time_as_str =
1355d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      base::UTF16ToUTF8(base::TimeFormatFriendlyDate(now));
1362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  TimedSigninStatusValue timed_value(value, time_as_str);
1372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  signin_status_.timed_signin_fields[field_index] = timed_value;
1392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Also persist these values in the prefs.
1412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  const std::string value_pref = SigninStatusFieldToString(field) + ".value";
142c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  const std::string time_pref = SigninStatusFieldToString(field) + ".time";
143e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch  client_->GetPrefs()->SetString(value_pref.c_str(), value);
144e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch  client_->GetPrefs()->SetString(time_pref.c_str(), time_as_str);
1452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  NotifyObservers();
1472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
1482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void AboutSigninInternals::RefreshSigninPrefs() {
150e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch  // Return if no client exists. Can occur in unit tests.
151e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch  if (!client_)
1522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return;
1532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
154e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch  PrefService* pref_service = client_->GetPrefs();
1552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  for (int i = UNTIMED_FIELDS_BEGIN; i < UNTIMED_FIELDS_END; ++i) {
1562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const std::string pref_path =
1572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        SigninStatusFieldToString(static_cast<UntimedSigninStatusField>(i));
1582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    signin_status_.untimed_signin_fields[i - UNTIMED_FIELDS_BEGIN] =
1602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        pref_service->GetString(pref_path.c_str());
1612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
162e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch  for (int i = TIMED_FIELDS_BEGIN; i < TIMED_FIELDS_END; ++i) {
163e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch    const std::string value_pref =
164e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch        SigninStatusFieldToString(static_cast<TimedSigninStatusField>(i)) +
165e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch        ".value";
166e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch    const std::string time_pref =
167e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch        SigninStatusFieldToString(static_cast<TimedSigninStatusField>(i)) +
168e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch        ".time";
1692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    TimedSigninStatusValue value(pref_service->GetString(value_pref.c_str()),
1712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                 pref_service->GetString(time_pref.c_str()));
1722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    signin_status_.timed_signin_fields[i - TIMED_FIELDS_BEGIN] = value;
1732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
1742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1754e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  // TODO(rogerta): Get status and timestamps for oauth2 tokens.
1762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  NotifyObservers();
1782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
1792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
180e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdochvoid AboutSigninInternals::Initialize(SigninClient* client) {
181e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch  DCHECK(!client_);
182e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch  client_ = client;
1832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  RefreshSigninPrefs();
1852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
186e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch  signin_manager_->AddSigninDiagnosticsObserver(this);
187e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch  token_service_->AddDiagnosticsObserver(this);
1882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
1892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1902a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void AboutSigninInternals::Shutdown() {
191e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch  signin_manager_->RemoveSigninDiagnosticsObserver(this);
192e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch  token_service_->RemoveDiagnosticsObserver(this);
1932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
1942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void AboutSigninInternals::NotifyObservers() {
1962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  FOR_EACH_OBSERVER(AboutSigninInternals::Observer,
1972a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                    signin_observers_,
198e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch                    OnSigninStateChanged(
199e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch                        signin_status_.ToValue(client_->GetProductVersion())));
2002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
2012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2025d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)scoped_ptr<base::DictionaryValue> AboutSigninInternals::GetSigninStatus() {
203e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch  return signin_status_.ToValue(client_->GetProductVersion()).Pass();
2042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
205c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
2065d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void AboutSigninInternals::OnAccessTokenRequested(
2075d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    const std::string& account_id,
2085d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    const std::string& consumer_id,
2095d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    const OAuth2TokenService::ScopeSet& scopes) {
2105d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  TokenInfo* token = signin_status_.FindToken(account_id, consumer_id, scopes);
2115d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (token) {
2125d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    *token = TokenInfo(consumer_id, scopes);
2135d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  } else {
2145d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    token = new TokenInfo(consumer_id, scopes);
2155d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    signin_status_.token_info_map[account_id].push_back(token);
2165d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
2175d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
2185d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  NotifyObservers();
2195d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
2205d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
2215d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void AboutSigninInternals::OnFetchAccessTokenComplete(
2225d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    const std::string& account_id,
2235d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    const std::string& consumer_id,
2245d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    const OAuth2TokenService::ScopeSet& scopes,
2255d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    GoogleServiceAuthError error,
2265d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    base::Time expiration_time) {
2275d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  TokenInfo* token = signin_status_.FindToken(account_id, consumer_id, scopes);
2285d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (!token) {
2295d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    DVLOG(1) << "Can't find token: " << account_id << ", " << consumer_id;
2305d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return;
2315d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
2325d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
2335d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  token->receive_time = base::Time::Now();
2345d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  token->error = error;
2355d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  token->expiration_time = expiration_time;
2365d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
2375d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  NotifyObservers();
2385d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
2395d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
2405d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void AboutSigninInternals::OnTokenRemoved(
2415d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    const std::string& account_id,
2425d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    const OAuth2TokenService::ScopeSet& scopes) {
2435d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  for (size_t i = 0; i < signin_status_.token_info_map[account_id].size();
244e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch       ++i) {
2455d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    TokenInfo* token = signin_status_.token_info_map[account_id][i];
2465d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    if (token->scopes == scopes)
2475d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      token->Invalidate();
2485d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
2495d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  NotifyObservers();
2505d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
2515d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
2525d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)AboutSigninInternals::TokenInfo::TokenInfo(
2535d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    const std::string& consumer_id,
2545d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    const OAuth2TokenService::ScopeSet& scopes)
2555d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    : consumer_id(consumer_id),
2565d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      scopes(scopes),
2575d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      request_time(base::Time::Now()),
2585d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      error(GoogleServiceAuthError::AuthErrorNone()),
259e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch      removed_(false) {}
2605d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
2615d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)AboutSigninInternals::TokenInfo::~TokenInfo() {}
2625d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
2635d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)bool AboutSigninInternals::TokenInfo::LessThan(const TokenInfo* a,
2645d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                               const TokenInfo* b) {
2655d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  return a->consumer_id < b->consumer_id || a->scopes < b->scopes;
2665d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
2675d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
268e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdochvoid AboutSigninInternals::TokenInfo::Invalidate() { removed_ = true; }
2695d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
2705d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)base::DictionaryValue* AboutSigninInternals::TokenInfo::ToValue() const {
2715d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  scoped_ptr<base::DictionaryValue> token_info(new base::DictionaryValue());
2725d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  token_info->SetString("service", consumer_id);
2735d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
2745d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  std::string scopes_str;
2755d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  for (OAuth2TokenService::ScopeSet::const_iterator it = scopes.begin();
276e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch       it != scopes.end();
277e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch       ++it) {
2785d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    scopes_str += *it + "<br/>";
2795d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
2805d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  token_info->SetString("scopes", scopes_str);
2815d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  token_info->SetString("request_time", GetTimeStr(request_time).c_str());
2825d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
2835d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (removed_) {
2845d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    token_info->SetString("status", "Token was revoked.");
2855d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  } else if (!receive_time.is_null()) {
2865d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    if (error == GoogleServiceAuthError::AuthErrorNone()) {
2875d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      bool token_expired = expiration_time < base::Time::Now();
2885d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      std::string status_str = "";
2895d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      if (token_expired)
2905d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        status_str = "<p style=\"color: #ffffff; background-color: #ff0000\">";
2915d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      base::StringAppendF(&status_str,
2925d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                          "Received token at %s. Expire at %s",
2935d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                          GetTimeStr(receive_time).c_str(),
2945d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                          GetTimeStr(expiration_time).c_str());
2955d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      if (token_expired)
2965d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        base::StringAppendF(&status_str, "</p>");
2975d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      token_info->SetString("status", status_str);
2985d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    } else {
2995d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      token_info->SetString(
3005d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)          "status",
301a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)          base::StringPrintf("Failure: %s", error.ToString().c_str()));
3025d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    }
3035d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  } else {
3045d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    token_info->SetString("status", "Waiting for response");
3055d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
3065d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
3075d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  return token_info.release();
3085d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
3095d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
3105d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)AboutSigninInternals::SigninStatus::SigninStatus()
311e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch    : untimed_signin_fields(UNTIMED_FIELDS_COUNT),
312e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch      timed_signin_fields(TIMED_FIELDS_COUNT) {}
3135d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
3145d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)AboutSigninInternals::SigninStatus::~SigninStatus() {
3155d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  for (TokenInfoMap::iterator it = token_info_map.begin();
316e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch       it != token_info_map.end();
317e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch       ++it) {
3185d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    STLDeleteElements(&it->second);
3195d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
3205d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
3215d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
322e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen MurdochAboutSigninInternals::TokenInfo* AboutSigninInternals::SigninStatus::FindToken(
3235d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    const std::string& account_id,
3245d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    const std::string& consumer_id,
3255d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    const OAuth2TokenService::ScopeSet& scopes) {
326e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch  for (size_t i = 0; i < token_info_map[account_id].size(); ++i) {
3275d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    TokenInfo* tmp = token_info_map[account_id][i];
3285d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    if (tmp->consumer_id == consumer_id && tmp->scopes == scopes)
3295d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      return tmp;
3305d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
3315d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  return NULL;
332c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
3335d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
334e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdochscoped_ptr<base::DictionaryValue> AboutSigninInternals::SigninStatus::ToValue(
335e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch    std::string product_version) {
3365d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  scoped_ptr<base::DictionaryValue> signin_status(new base::DictionaryValue());
3375d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  base::ListValue* signin_info = new base::ListValue();
3385d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  signin_status->Set("signin_info", signin_info);
3395d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
3405d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // A summary of signin related info first.
3415d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  base::ListValue* basic_info = AddSection(signin_info, "Basic Information");
3425d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  const std::string signin_status_string =
343e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch      untimed_signin_fields[USERNAME - UNTIMED_FIELDS_BEGIN].empty()
344e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch          ? "Not Signed In"
345e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch          : "Signed In";
346e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch  AddSectionEntry(basic_info, "Chrome Version", product_version);
3475d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  AddSectionEntry(basic_info, "Signin Status", signin_status_string);
3485d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
3495d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // Only add username.  SID and LSID have moved to tokens section.
3505d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  const std::string field =
3515d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      SigninStatusFieldToLabel(static_cast<UntimedSigninStatusField>(USERNAME));
352e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch  AddSectionEntry(basic_info,
353e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch                  field,
354e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch                  untimed_signin_fields[USERNAME - UNTIMED_FIELDS_BEGIN]);
3555d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
3565d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // Time and status information of the possible sign in types.
357e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch  base::ListValue* detailed_info =
358e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch      AddSection(signin_info, "Last Signin Details");
3595d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  for (int i = TIMED_FIELDS_BEGIN; i < TIMED_FIELDS_END; ++i) {
3605d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    const std::string value_field =
3615d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        SigninStatusFieldToLabel(static_cast<TimedSigninStatusField>(i)).first;
3625d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    const std::string time_field =
3635d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        SigninStatusFieldToLabel(static_cast<TimedSigninStatusField>(i)).second;
3645d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
365e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch    AddSectionEntry(detailed_info,
366e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch                    value_field,
3675d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                    timed_signin_fields[i - TIMED_FIELDS_BEGIN].first);
368e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch    AddSectionEntry(detailed_info,
369e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch                    time_field,
3705d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                    timed_signin_fields[i - TIMED_FIELDS_BEGIN].second);
3715d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
3725d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
3735d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // Token information for all services.
3745d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  base::ListValue* token_info = new base::ListValue();
3755d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  signin_status->Set("token_info", token_info);
3765d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  for (TokenInfoMap::iterator it = token_info_map.begin();
377e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch       it != token_info_map.end();
378e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch       ++it) {
3795d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    base::ListValue* token_details = AddSection(token_info, it->first);
3805d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
3815d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    std::sort(it->second.begin(), it->second.end(), TokenInfo::LessThan);
3825d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    const std::vector<TokenInfo*>& tokens = it->second;
3835d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    for (size_t i = 0; i < tokens.size(); ++i) {
3845d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      base::DictionaryValue* token_info = tokens[i]->ToValue();
3855d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      token_details->Append(token_info);
3865d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    }
3875d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
3885d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
3895d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  return signin_status.Pass();
3905d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
391