1// Copyright 2014 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#ifndef EXTENSIONS_BROWSER_APP_WINDOW_APP_WINDOW_GEOMETRY_CACHE_H_
6#define EXTENSIONS_BROWSER_APP_WINDOW_APP_WINDOW_GEOMETRY_CACHE_H_
7
8#include <map>
9#include <set>
10#include <string>
11
12#include "base/memory/scoped_ptr.h"
13#include "base/memory/singleton.h"
14#include "base/observer_list.h"
15#include "base/scoped_observer.h"
16#include "base/time/time.h"
17#include "base/timer/timer.h"
18#include "base/values.h"
19#include "components/keyed_service/content/browser_context_keyed_service_factory.h"
20#include "components/keyed_service/core/keyed_service.h"
21#include "extensions/browser/extension_registry_observer.h"
22#include "ui/base/ui_base_types.h"
23#include "ui/gfx/rect.h"
24
25namespace extensions {
26
27class ExtensionPrefs;
28class ExtensionRegistry;
29
30// A cache for persisted geometry of app windows, both to not have to wait
31// for IO when creating a new window, and to not cause IO on every window
32// geometry change.
33class AppWindowGeometryCache : public KeyedService,
34                               public ExtensionRegistryObserver {
35 public:
36  class Factory : public BrowserContextKeyedServiceFactory {
37   public:
38    static AppWindowGeometryCache* GetForContext(
39        content::BrowserContext* context,
40        bool create);
41
42    static Factory* GetInstance();
43
44   private:
45    friend struct DefaultSingletonTraits<Factory>;
46
47    Factory();
48    virtual ~Factory();
49
50    // BrowserContextKeyedServiceFactory
51    virtual KeyedService* BuildServiceInstanceFor(
52        content::BrowserContext* context) const OVERRIDE;
53    virtual bool ServiceIsNULLWhileTesting() const OVERRIDE;
54    virtual content::BrowserContext* GetBrowserContextToUse(
55        content::BrowserContext* context) const OVERRIDE;
56  };
57
58  class Observer {
59   public:
60    virtual void OnGeometryCacheChanged(const std::string& extension_id,
61                                        const std::string& window_id,
62                                        const gfx::Rect& bounds) = 0;
63
64   protected:
65    virtual ~Observer() {}
66  };
67
68  AppWindowGeometryCache(content::BrowserContext* context,
69                         ExtensionPrefs* prefs);
70
71  virtual ~AppWindowGeometryCache();
72
73  // Returns the instance for the given browsing context.
74  static AppWindowGeometryCache* Get(content::BrowserContext* context);
75
76  // Save the geometry and state associated with |extension_id| and |window_id|.
77  void SaveGeometry(const std::string& extension_id,
78                    const std::string& window_id,
79                    const gfx::Rect& bounds,
80                    const gfx::Rect& screen_bounds,
81                    ui::WindowShowState state);
82
83  // Get any saved geometry and state associated with |extension_id| and
84  // |window_id|. If saved data exists, sets |bounds|, |screen_bounds| and
85  // |state| if not NULL and returns true.
86  bool GetGeometry(const std::string& extension_id,
87                   const std::string& window_id,
88                   gfx::Rect* bounds,
89                   gfx::Rect* screen_bounds,
90                   ui::WindowShowState* state);
91
92  // KeyedService
93  virtual void Shutdown() OVERRIDE;
94
95  void AddObserver(Observer* observer);
96  void RemoveObserver(Observer* observer);
97
98  // Maximum number of windows we'll cache the geometry for per app.
99  static const size_t kMaxCachedWindows = 100;
100
101 protected:
102  friend class AppWindowGeometryCacheTest;
103
104  // For tests, this modifies the timeout delay for saving changes from calls
105  // to SaveGeometry. (Note that even if this is set to 0, you still need to
106  // run the message loop to see the results of any SyncToStorage call).
107  void SetSyncDelayForTests(int timeout_ms);
108
109 private:
110  // Data stored for each window.
111  struct WindowData {
112    WindowData();
113    ~WindowData();
114    gfx::Rect bounds;
115    gfx::Rect screen_bounds;
116    ui::WindowShowState window_state;
117    base::Time last_change;
118  };
119
120  // Data stored for each extension.
121  typedef std::map<std::string, WindowData> ExtensionData;
122
123  // ExtensionRegistryObserver implementation.
124  virtual void OnExtensionLoaded(content::BrowserContext* browser_context,
125                                 const Extension* extension) OVERRIDE;
126  virtual void OnExtensionUnloaded(
127      content::BrowserContext* browser_context,
128      const Extension* extension,
129      UnloadedExtensionInfo::Reason reason) OVERRIDE;
130
131  void LoadGeometryFromStorage(const std::string& extension_id);
132  void SyncToStorage();
133
134  // Preferences storage.
135  ExtensionPrefs* prefs_;
136
137  // Cached data.
138  std::map<std::string, ExtensionData> cache_;
139
140  // Data that still needs saving.
141  std::set<std::string> unsynced_extensions_;
142
143  // The timer used to save the data.
144  base::OneShotTimer<AppWindowGeometryCache> sync_timer_;
145
146  // The timeout value we'll use for |sync_timer_|.
147  base::TimeDelta sync_delay_;
148
149  // Listen to extension load, unloaded notifications.
150  ScopedObserver<ExtensionRegistry, ExtensionRegistryObserver>
151      extension_registry_observer_;
152
153  ObserverList<Observer> observers_;
154};
155
156}  // namespace extensions
157
158#endif  // EXTENSIONS_BROWSER_APP_WINDOW_APP_WINDOW_GEOMETRY_CACHE_H_
159