Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(130)

Side by Side Diff: content/browser/accessibility/browser_accessibility_manager_android.cc

Issue 2903583006: Collect metrics on running Accessibility services on Android (Closed)
Patch Set: aelias Created 3 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 // Copyright 2013 The Chromium Authors. All rights reserved. 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 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "content/browser/accessibility/browser_accessibility_manager_android.h" 5 #include "content/browser/accessibility/browser_accessibility_manager_android.h"
6 6
7 #include <stddef.h> 7 #include <stddef.h>
8 8
9 #include <cmath> 9 #include <cmath>
10 10
11 #include "base/android/jni_android.h" 11 #include "base/android/jni_android.h"
12 #include "base/android/jni_string.h" 12 #include "base/android/jni_string.h"
13 #include "base/feature_list.h" 13 #include "base/feature_list.h"
14 #include "base/i18n/char_iterator.h" 14 #include "base/i18n/char_iterator.h"
15 #include "base/macros.h"
16 #include "base/metrics/histogram_macros.h"
15 #include "base/strings/string_number_conversions.h" 17 #include "base/strings/string_number_conversions.h"
16 #include "base/strings/utf_string_conversions.h" 18 #include "base/strings/utf_string_conversions.h"
17 #include "base/values.h" 19 #include "base/values.h"
18 #include "content/app/strings/grit/content_strings.h" 20 #include "content/app/strings/grit/content_strings.h"
19 #include "content/browser/accessibility/browser_accessibility_android.h" 21 #include "content/browser/accessibility/browser_accessibility_android.h"
20 #include "content/browser/accessibility/one_shot_accessibility_tree_search.h" 22 #include "content/browser/accessibility/one_shot_accessibility_tree_search.h"
21 #include "content/common/accessibility_messages.h" 23 #include "content/common/accessibility_messages.h"
22 #include "content/public/common/content_features.h" 24 #include "content/public/common/content_features.h"
23 #include "jni/BrowserAccessibilityManager_jni.h" 25 #include "jni/BrowserAccessibilityManager_jni.h"
24 #include "ui/accessibility/ax_text_utils.h" 26 #include "ui/accessibility/ax_text_utils.h"
25 27
26 using base::android::AttachCurrentThread; 28 using base::android::AttachCurrentThread;
27 using base::android::JavaParamRef; 29 using base::android::JavaParamRef;
28 using base::android::ScopedJavaLocalRef; 30 using base::android::ScopedJavaLocalRef;
29 31
30 namespace content { 32 namespace content {
31 33
32 namespace { 34 namespace {
33 35
36 // IMPORTANT!
37 // These values are written to logs. Do not renumber or delete
38 // existing items; add new entries to the end of the list.
39 enum {
40 UMA_CAPABILITY_CAN_CONTROL_MAGNIFICATION = 0,
41 UMA_CAPABILITY_CAN_PERFORM_GESTURES = 1,
42 UMA_CAPABILITY_CAN_REQUEST_ENHANCED_WEB_ACCESSIBILITY = 2,
43 UMA_CAPABILITY_CAN_REQUEST_FILTER_KEY_EVENTS = 3,
44 UMA_CAPABILITY_CAN_REQUEST_TOUCH_EXPLORATION = 4,
45 UMA_CAPABILITY_CAN_RETRIEVE_WINDOW_CONTENT = 5,
46 UMA_EVENT_ANNOUNCEMENT = 6,
47 UMA_EVENT_ASSIST_READING_CONTEXT = 7,
48 UMA_EVENT_GESTURE_DETECTION_END = 8,
49 UMA_EVENT_GESTURE_DETECTION_START = 9,
50 UMA_EVENT_NOTIFICATION_STATE_CHANGED = 10,
51 UMA_EVENT_TOUCH_EXPLORATION_GESTURE_END = 11,
52 UMA_EVENT_TOUCH_EXPLORATION_GESTURE_START = 12,
53 UMA_EVENT_TOUCH_INTERACTION_END = 13,
54 UMA_EVENT_TOUCH_INTERACTION_START = 14,
55 UMA_EVENT_VIEW_ACCESSIBILITY_FOCUSED = 15,
56 UMA_EVENT_VIEW_ACCESSIBILITY_FOCUS_CLEARED = 16,
57 UMA_EVENT_VIEW_CLICKED = 17,
58 UMA_EVENT_VIEW_CONTEXT_CLICKED = 18,
59 UMA_EVENT_VIEW_FOCUSED = 19,
60 UMA_EVENT_VIEW_HOVER_ENTER = 20,
61 UMA_EVENT_VIEW_HOVER_EXIT = 21,
62 UMA_EVENT_VIEW_LONG_CLICKED = 22,
63 UMA_EVENT_VIEW_SCROLLED = 23,
64 UMA_EVENT_VIEW_SELECTED = 24,
65 UMA_EVENT_VIEW_TEXT_CHANGED = 25,
66 UMA_EVENT_VIEW_TEXT_SELECTION_CHANGED = 26,
67 UMA_EVENT_VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY = 27,
68 UMA_EVENT_WINDOWS_CHANGED = 28,
69 UMA_EVENT_WINDOW_CONTENT_CHANGED = 29,
70 UMA_EVENT_WINDOW_STATE_CHANGED = 30,
71 UMA_FEEDBACK_AUDIBLE = 31,
72 UMA_FEEDBACK_BRAILLE = 32,
73 UMA_FEEDBACK_GENERIC = 33,
74 UMA_FEEDBACK_HAPTIC = 34,
75 UMA_FEEDBACK_SPOKEN = 35,
76 UMA_FEEDBACK_VISUAL = 36,
77 UMA_FLAG_FORCE_DIRECT_BOOT_AWARE = 37,
78 UMA_FLAG_INCLUDE_NOT_IMPORTANT_VIEWS = 38,
79 UMA_FLAG_REPORT_VIEW_IDS = 39,
80 UMA_FLAG_REQUEST_ENHANCED_WEB_ACCESSIBILITY = 40,
81 UMA_FLAG_REQUEST_FILTER_KEY_EVENTS = 41,
82 UMA_FLAG_REQUEST_TOUCH_EXPLORATION_MODE = 42,
83 UMA_FLAG_RETRIEVE_INTERACTIVE_WINDOWS = 43,
84
85 // This must always be the last enum. It's okay for its value to
86 // increase, but none of the other enum values may change.
87 UMA_ACCESSIBILITYSERVICEINFO_MAX
88 };
89
90 #define EVENT_TYPE_HISTOGRAM(event_type_mask, event_type) \
91 if (event_type_mask & ACCESSIBILITYEVENT_TYPE_##event_type) \
92 UMA_HISTOGRAM_ENUMERATION("Accessibility.AndroidServiceInfo", \
93 UMA_EVENT_##event_type, \
94 UMA_ACCESSIBILITYSERVICEINFO_MAX)
95 #define FLAGS_HISTOGRAM(flags_mask, flag) \
96 if (flags_mask & ACCESSIBILITYSERVICEINFO_FLAG_##flag) \
97 UMA_HISTOGRAM_ENUMERATION("Accessibility.AndroidServiceInfo", \
98 UMA_FLAG_##flag, UMA_ACCESSIBILITYSERVICEINFO_MAX)
99 #define FEEDBACK_TYPE_HISTOGRAM(feedback_type_mask, feedback_type) \
100 if (feedback_type_mask & ACCESSIBILITYSERVICEINFO_FEEDBACK_##feedback_type) \
101 UMA_HISTOGRAM_ENUMERATION("Accessibility.AndroidServiceInfo", \
102 UMA_FEEDBACK_##feedback_type, \
103 UMA_ACCESSIBILITYSERVICEINFO_MAX)
104 #define CAPABILITY_TYPE_HISTOGRAM(capability_type_mask, capability_type) \
105 if (capability_type_mask & \
106 ACCESSIBILITYSERVICEINFO_CAPABILITY_##capability_type) \
107 UMA_HISTOGRAM_ENUMERATION("Accessibility.AndroidServiceInfo", \
108 UMA_CAPABILITY_##capability_type, \
109 UMA_ACCESSIBILITYSERVICEINFO_MAX)
110
111 // These are constants from
112 // android.view.accessibility.AccessibilityEvent in Java:
113 enum {
114 ACCESSIBILITYEVENT_TYPE_ANNOUNCEMENT = 0x00004000,
115 ACCESSIBILITYEVENT_TYPE_ASSIST_READING_CONTEXT = 0x01000000,
116 ACCESSIBILITYEVENT_TYPE_GESTURE_DETECTION_END = 0x00080000,
117 ACCESSIBILITYEVENT_TYPE_GESTURE_DETECTION_START = 0x00040000,
118 ACCESSIBILITYEVENT_TYPE_NOTIFICATION_STATE_CHANGED = 0x00000040,
119 ACCESSIBILITYEVENT_TYPE_TOUCH_EXPLORATION_GESTURE_END = 0x00000400,
120 ACCESSIBILITYEVENT_TYPE_TOUCH_EXPLORATION_GESTURE_START = 0x00000200,
121 ACCESSIBILITYEVENT_TYPE_TOUCH_INTERACTION_END = 0x00200000,
122 ACCESSIBILITYEVENT_TYPE_TOUCH_INTERACTION_START = 0x00100000,
123 ACCESSIBILITYEVENT_TYPE_VIEW_ACCESSIBILITY_FOCUSED = 0x00008000,
124 ACCESSIBILITYEVENT_TYPE_VIEW_ACCESSIBILITY_FOCUS_CLEARED = 0x00010000,
125 ACCESSIBILITYEVENT_TYPE_VIEW_CLICKED = 0x00000001,
126 ACCESSIBILITYEVENT_TYPE_VIEW_CONTEXT_CLICKED = 0x00800000,
127 ACCESSIBILITYEVENT_TYPE_VIEW_FOCUSED = 0x00000008,
128 ACCESSIBILITYEVENT_TYPE_VIEW_HOVER_ENTER = 0x00000080,
129 ACCESSIBILITYEVENT_TYPE_VIEW_HOVER_EXIT = 0x00000100,
130 ACCESSIBILITYEVENT_TYPE_VIEW_LONG_CLICKED = 0x00000002,
131 ACCESSIBILITYEVENT_TYPE_VIEW_SCROLLED = 0x00001000,
132 ACCESSIBILITYEVENT_TYPE_VIEW_SELECTED = 0x00000004,
133 ACCESSIBILITYEVENT_TYPE_VIEW_TEXT_CHANGED = 0x00000010,
134 ACCESSIBILITYEVENT_TYPE_VIEW_TEXT_SELECTION_CHANGED = 0x00002000,
135 ACCESSIBILITYEVENT_TYPE_VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY =
136 0x00020000,
137 ACCESSIBILITYEVENT_TYPE_WINDOWS_CHANGED = 0x00400000,
138 ACCESSIBILITYEVENT_TYPE_WINDOW_CONTENT_CHANGED = 0x00000800,
139 ACCESSIBILITYEVENT_TYPE_WINDOW_STATE_CHANGED = 0x00000020
140 };
141
142 // These are constants from
143 // android.accessibilityservice.AccessibilityServiceInfo in Java:
144 enum {
145 ACCESSIBILITYSERVICEINFO_CAPABILITY_CAN_RETRIEVE_WINDOW_CONTENT = 0x00000001,
146 ACCESSIBILITYSERVICEINFO_CAPABILITY_CAN_REQUEST_TOUCH_EXPLORATION =
147 0x00000002,
148 ACCESSIBILITYSERVICEINFO_CAPABILITY_CAN_REQUEST_ENHANCED_WEB_ACCESSIBILITY =
149 0x00000004,
150 ACCESSIBILITYSERVICEINFO_CAPABILITY_CAN_REQUEST_FILTER_KEY_EVENTS =
151 0x00000008,
152 ACCESSIBILITYSERVICEINFO_CAPABILITY_CAN_CONTROL_MAGNIFICATION = 0x00000010,
153 ACCESSIBILITYSERVICEINFO_CAPABILITY_CAN_PERFORM_GESTURES = 0x00000020,
154 ACCESSIBILITYSERVICEINFO_FEEDBACK_SPOKEN = 0x0000001,
155 ACCESSIBILITYSERVICEINFO_FEEDBACK_HAPTIC = 0x0000002,
156 ACCESSIBILITYSERVICEINFO_FEEDBACK_AUDIBLE = 0x0000004,
157 ACCESSIBILITYSERVICEINFO_FEEDBACK_VISUAL = 0x0000008,
158 ACCESSIBILITYSERVICEINFO_FEEDBACK_GENERIC = 0x0000010,
159 ACCESSIBILITYSERVICEINFO_FEEDBACK_BRAILLE = 0x0000020,
160 ACCESSIBILITYSERVICEINFO_FLAG_INCLUDE_NOT_IMPORTANT_VIEWS = 0x0000002,
161 ACCESSIBILITYSERVICEINFO_FLAG_REQUEST_TOUCH_EXPLORATION_MODE = 0x0000004,
162 ACCESSIBILITYSERVICEINFO_FLAG_REQUEST_ENHANCED_WEB_ACCESSIBILITY = 0x00000008,
163 ACCESSIBILITYSERVICEINFO_FLAG_REPORT_VIEW_IDS = 0x00000010,
164 ACCESSIBILITYSERVICEINFO_FLAG_REQUEST_FILTER_KEY_EVENTS = 0x00000020,
165 ACCESSIBILITYSERVICEINFO_FLAG_RETRIEVE_INTERACTIVE_WINDOWS = 0x00000040,
166 ACCESSIBILITYSERVICEINFO_FLAG_FORCE_DIRECT_BOOT_AWARE = 0x00010000,
167 };
168
34 using SearchKeyToPredicateMap = 169 using SearchKeyToPredicateMap =
35 base::hash_map<base::string16, AccessibilityMatchPredicate>; 170 base::hash_map<base::string16, AccessibilityMatchPredicate>;
36 base::LazyInstance<SearchKeyToPredicateMap>::DestructorAtExit 171 base::LazyInstance<SearchKeyToPredicateMap>::DestructorAtExit
37 g_search_key_to_predicate_map = LAZY_INSTANCE_INITIALIZER; 172 g_search_key_to_predicate_map = LAZY_INSTANCE_INITIALIZER;
38 base::LazyInstance<base::string16>::DestructorAtExit g_all_search_keys = 173 base::LazyInstance<base::string16>::DestructorAtExit g_all_search_keys =
39 LAZY_INSTANCE_INITIALIZER; 174 LAZY_INSTANCE_INITIALIZER;
40 175
41 bool SectionPredicate( 176 bool SectionPredicate(
42 BrowserAccessibility* start, BrowserAccessibility* node) { 177 BrowserAccessibility* start, BrowserAccessibility* node) {
43 switch (node->GetRole()) { 178 switch (node->GetRole()) {
(...skipping 119 matching lines...) Expand 10 before | Expand all | Expand 10 after
163 298
164 BrowserAccessibilityManagerAndroid::BrowserAccessibilityManagerAndroid( 299 BrowserAccessibilityManagerAndroid::BrowserAccessibilityManagerAndroid(
165 ScopedJavaLocalRef<jobject> content_view_core, 300 ScopedJavaLocalRef<jobject> content_view_core,
166 const ui::AXTreeUpdate& initial_tree, 301 const ui::AXTreeUpdate& initial_tree,
167 BrowserAccessibilityDelegate* delegate, 302 BrowserAccessibilityDelegate* delegate,
168 BrowserAccessibilityFactory* factory) 303 BrowserAccessibilityFactory* factory)
169 : BrowserAccessibilityManager(delegate, factory), 304 : BrowserAccessibilityManager(delegate, factory),
170 prune_tree_for_screen_reader_(true) { 305 prune_tree_for_screen_reader_(true) {
171 Initialize(initial_tree); 306 Initialize(initial_tree);
172 SetContentViewCore(content_view_core); 307 SetContentViewCore(content_view_core);
308 CollectStats();
173 } 309 }
174 310
175 BrowserAccessibilityManagerAndroid::~BrowserAccessibilityManagerAndroid() { 311 BrowserAccessibilityManagerAndroid::~BrowserAccessibilityManagerAndroid() {
176 JNIEnv* env = AttachCurrentThread(); 312 JNIEnv* env = AttachCurrentThread();
177 ScopedJavaLocalRef<jobject> obj = GetJavaRefFromRootManager(); 313 ScopedJavaLocalRef<jobject> obj = GetJavaRefFromRootManager();
178 if (obj.is_null()) 314 if (obj.is_null())
179 return; 315 return;
180 316
181 // Clean up autofill popup proxy node in case the popup was not dismissed. 317 // Clean up autofill popup proxy node in case the popup was not dismissed.
182 DeleteAutofillPopupProxy(); 318 DeleteAutofillPopupProxy();
(...skipping 917 matching lines...) Expand 10 before | Expand all | Expand 10 after
1100 BrowserAccessibilityManagerAndroid* root_manager = 1236 BrowserAccessibilityManagerAndroid* root_manager =
1101 static_cast<BrowserAccessibilityManagerAndroid*>( 1237 static_cast<BrowserAccessibilityManagerAndroid*>(
1102 GetRootManager()); 1238 GetRootManager());
1103 if (!root_manager) 1239 if (!root_manager)
1104 return ScopedJavaLocalRef<jobject>(); 1240 return ScopedJavaLocalRef<jobject>();
1105 1241
1106 JNIEnv* env = AttachCurrentThread(); 1242 JNIEnv* env = AttachCurrentThread();
1107 return root_manager->java_ref().get(env); 1243 return root_manager->java_ref().get(env);
1108 } 1244 }
1109 1245
1246 void BrowserAccessibilityManagerAndroid::CollectStats() {
1247 JNIEnv* env = AttachCurrentThread();
1248 ScopedJavaLocalRef<jobject> obj = GetJavaRefFromRootManager();
1249 if (obj.is_null())
1250 return;
1251
1252 int event_type_mask =
1253 Java_BrowserAccessibilityManager_getAccessibilityServiceEventTypeMask(
1254 env, obj);
1255 EVENT_TYPE_HISTOGRAM(event_type_mask, ANNOUNCEMENT);
1256 EVENT_TYPE_HISTOGRAM(event_type_mask, ANNOUNCEMENT);
aelias_OOO_until_Jul13 2017/05/24 21:44:50 Looks like you're counting this twice by accident.
dmazzoni 2017/05/25 21:04:52 Done.
1257 EVENT_TYPE_HISTOGRAM(event_type_mask, ASSIST_READING_CONTEXT);
1258 EVENT_TYPE_HISTOGRAM(event_type_mask, GESTURE_DETECTION_END);
1259 EVENT_TYPE_HISTOGRAM(event_type_mask, GESTURE_DETECTION_START);
1260 EVENT_TYPE_HISTOGRAM(event_type_mask, NOTIFICATION_STATE_CHANGED);
1261 EVENT_TYPE_HISTOGRAM(event_type_mask, TOUCH_EXPLORATION_GESTURE_END);
1262 EVENT_TYPE_HISTOGRAM(event_type_mask, TOUCH_EXPLORATION_GESTURE_START);
1263 EVENT_TYPE_HISTOGRAM(event_type_mask, TOUCH_INTERACTION_END);
1264 EVENT_TYPE_HISTOGRAM(event_type_mask, TOUCH_INTERACTION_START);
1265 EVENT_TYPE_HISTOGRAM(event_type_mask, VIEW_ACCESSIBILITY_FOCUSED);
1266 EVENT_TYPE_HISTOGRAM(event_type_mask, VIEW_ACCESSIBILITY_FOCUS_CLEARED);
1267 EVENT_TYPE_HISTOGRAM(event_type_mask, VIEW_CLICKED);
1268 EVENT_TYPE_HISTOGRAM(event_type_mask, VIEW_CONTEXT_CLICKED);
1269 EVENT_TYPE_HISTOGRAM(event_type_mask, VIEW_FOCUSED);
1270 EVENT_TYPE_HISTOGRAM(event_type_mask, VIEW_HOVER_ENTER);
1271 EVENT_TYPE_HISTOGRAM(event_type_mask, VIEW_HOVER_EXIT);
1272 EVENT_TYPE_HISTOGRAM(event_type_mask, VIEW_LONG_CLICKED);
1273 EVENT_TYPE_HISTOGRAM(event_type_mask, VIEW_SCROLLED);
1274 EVENT_TYPE_HISTOGRAM(event_type_mask, VIEW_SELECTED);
1275 EVENT_TYPE_HISTOGRAM(event_type_mask, VIEW_TEXT_CHANGED);
1276 EVENT_TYPE_HISTOGRAM(event_type_mask, VIEW_TEXT_SELECTION_CHANGED);
1277 EVENT_TYPE_HISTOGRAM(event_type_mask,
1278 VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY);
1279 EVENT_TYPE_HISTOGRAM(event_type_mask, WINDOWS_CHANGED);
1280 EVENT_TYPE_HISTOGRAM(event_type_mask, WINDOW_CONTENT_CHANGED);
1281 EVENT_TYPE_HISTOGRAM(event_type_mask, WINDOW_STATE_CHANGED);
1282
1283 int feedback_type_mask =
1284 Java_BrowserAccessibilityManager_getAccessibilityServiceFeedbackTypeMask(
1285 env, obj);
1286 FEEDBACK_TYPE_HISTOGRAM(feedback_type_mask, SPOKEN);
1287 FEEDBACK_TYPE_HISTOGRAM(feedback_type_mask, HAPTIC);
1288 FEEDBACK_TYPE_HISTOGRAM(feedback_type_mask, AUDIBLE);
1289 FEEDBACK_TYPE_HISTOGRAM(feedback_type_mask, VISUAL);
1290 FEEDBACK_TYPE_HISTOGRAM(feedback_type_mask, GENERIC);
1291 FEEDBACK_TYPE_HISTOGRAM(feedback_type_mask, BRAILLE);
1292
1293 int flags_mask =
1294 Java_BrowserAccessibilityManager_getAccessibilityServiceFlagsMask(env,
1295 obj);
1296 FLAGS_HISTOGRAM(flags_mask, INCLUDE_NOT_IMPORTANT_VIEWS);
1297 FLAGS_HISTOGRAM(flags_mask, REQUEST_TOUCH_EXPLORATION_MODE);
1298 FLAGS_HISTOGRAM(flags_mask, REQUEST_ENHANCED_WEB_ACCESSIBILITY);
1299 FLAGS_HISTOGRAM(flags_mask, REPORT_VIEW_IDS);
1300 FLAGS_HISTOGRAM(flags_mask, REQUEST_FILTER_KEY_EVENTS);
1301 FLAGS_HISTOGRAM(flags_mask, RETRIEVE_INTERACTIVE_WINDOWS);
1302 FLAGS_HISTOGRAM(flags_mask, FORCE_DIRECT_BOOT_AWARE);
1303
1304 int capabilities_mask =
1305 Java_BrowserAccessibilityManager_getAccessibilityServiceCapabilitiesMask(
1306 env, obj);
1307 CAPABILITY_TYPE_HISTOGRAM(capabilities_mask, CAN_RETRIEVE_WINDOW_CONTENT);
1308 CAPABILITY_TYPE_HISTOGRAM(capabilities_mask, CAN_REQUEST_TOUCH_EXPLORATION);
1309 CAPABILITY_TYPE_HISTOGRAM(capabilities_mask,
1310 CAN_REQUEST_ENHANCED_WEB_ACCESSIBILITY);
1311 CAPABILITY_TYPE_HISTOGRAM(capabilities_mask, CAN_REQUEST_FILTER_KEY_EVENTS);
1312 CAPABILITY_TYPE_HISTOGRAM(capabilities_mask, CAN_CONTROL_MAGNIFICATION);
1313 CAPABILITY_TYPE_HISTOGRAM(capabilities_mask, CAN_PERFORM_GESTURES);
1314 }
1315
1110 bool RegisterBrowserAccessibilityManager(JNIEnv* env) { 1316 bool RegisterBrowserAccessibilityManager(JNIEnv* env) {
1111 return RegisterNativesImpl(env); 1317 return RegisterNativesImpl(env);
1112 } 1318 }
1113 1319
1114 } // namespace content 1320 } // namespace content
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698