• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  *  Copyright (C) 2012 Samsung Electronics
3  *
4  *  This library is free software; you can redistribute it and/or
5  *  modify it under the terms of the GNU Library General Public
6  *  License as published by the Free Software Foundation; either
7  *  version 2 of the License, or (at your option) any later version.
8  *
9  *  This library is distributed in the hope that it will be useful,
10  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
11  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  *  Library General Public License for more details.
13  *
14  *  You should have received a copy of the GNU Library General Public License
15  *  along with this library; see the file COPYING.LIB.  If not, write to
16  *  the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
17  *  Boston, MA 02110-1301, USA.
18  */
19 
20 #include "config.h"
21 #include "modules/vibration/NavigatorVibration.h"
22 
23 #include "core/frame/LocalFrame.h"
24 #include "core/frame/Navigator.h"
25 #include "core/page/PageVisibilityState.h"
26 #include "public/platform/Platform.h"
27 #include "public/platform/WebVibration.h"
28 
29 namespace blink {
30 
31 // Maximum number of entries in a vibration pattern.
32 const unsigned kVibrationPatternLengthMax = 99;
33 
NavigatorVibration(Page & page)34 NavigatorVibration::NavigatorVibration(Page& page)
35     : PageLifecycleObserver(&page)
36     , m_timerStart(this, &NavigatorVibration::timerStartFired)
37     , m_timerStop(this, &NavigatorVibration::timerStopFired)
38     , m_isVibrating(false)
39 {
40 }
41 
~NavigatorVibration()42 NavigatorVibration::~NavigatorVibration()
43 {
44     if (m_isVibrating)
45         cancelVibration();
46 }
47 
vibrate(const VibrationPattern & pattern)48 bool NavigatorVibration::vibrate(const VibrationPattern& pattern)
49 {
50     VibrationPattern sanitized = pattern;
51     size_t length = sanitized.size();
52 
53     // If the pattern is too long then truncate it.
54     if (length > kVibrationPatternLengthMax) {
55         sanitized.shrink(kVibrationPatternLengthMax);
56         length = kVibrationPatternLengthMax;
57     }
58 
59     // If any pattern entry is too long then truncate it.
60     for (size_t i = 0; i < length; ++i) {
61         if (sanitized[i] > kVibrationDurationMax)
62             sanitized[i] = kVibrationDurationMax;
63     }
64 
65     // If the last item in the pattern is a pause then discard it.
66     if (length && !(length % 2))
67         sanitized.removeLast();
68 
69     // Cancelling clears the stored pattern so do it before setting the new one.
70     if (m_isVibrating)
71         cancelVibration();
72 
73     m_pattern = sanitized;
74 
75     if (m_timerStart.isActive())
76         m_timerStart.stop();
77 
78     if (!m_pattern.size())
79         return true;
80 
81     if (m_pattern.size() == 1 && !m_pattern[0]) {
82         m_pattern.clear();
83         return true;
84     }
85 
86     m_timerStart.startOneShot(0, FROM_HERE);
87     m_isVibrating = true;
88     return true;
89 }
90 
cancelVibration()91 void NavigatorVibration::cancelVibration()
92 {
93     m_pattern.clear();
94     if (m_isVibrating) {
95         Platform::current()->cancelVibration();
96         m_isVibrating = false;
97         m_timerStop.stop();
98     }
99 }
100 
timerStartFired(Timer<NavigatorVibration> * timer)101 void NavigatorVibration::timerStartFired(Timer<NavigatorVibration>* timer)
102 {
103     ASSERT_UNUSED(timer, timer == &m_timerStart);
104 
105     if (m_pattern.size()) {
106         m_isVibrating = true;
107         Platform::current()->vibrate(m_pattern[0]);
108         m_timerStop.startOneShot(m_pattern[0] / 1000.0, FROM_HERE);
109         m_pattern.remove(0);
110     }
111 }
112 
timerStopFired(Timer<NavigatorVibration> * timer)113 void NavigatorVibration::timerStopFired(Timer<NavigatorVibration>* timer)
114 {
115     ASSERT_UNUSED(timer, timer == &m_timerStop);
116 
117     if (m_pattern.isEmpty())
118         m_isVibrating = false;
119 
120     if (m_pattern.size()) {
121         m_timerStart.startOneShot(m_pattern[0] / 1000.0, FROM_HERE);
122         m_pattern.remove(0);
123     }
124 }
125 
pageVisibilityChanged()126 void NavigatorVibration::pageVisibilityChanged()
127 {
128     if (page()->visibilityState() != PageVisibilityStateVisible)
129         cancelVibration();
130 }
131 
didCommitLoad(LocalFrame * frame)132 void NavigatorVibration::didCommitLoad(LocalFrame* frame)
133 {
134     // A new load has been committed, which means the current page will be
135     // unloaded. Cancel all running vibrations.
136     cancelVibration();
137 }
138 
vibrate(Navigator & navigator,unsigned time)139 bool NavigatorVibration::vibrate(Navigator& navigator, unsigned time)
140 {
141     VibrationPattern pattern;
142     pattern.append(time);
143     return NavigatorVibration::vibrate(navigator, pattern);
144 }
145 
vibrate(Navigator & navigator,const VibrationPattern & pattern)146 bool NavigatorVibration::vibrate(Navigator& navigator, const VibrationPattern& pattern)
147 {
148     if (!navigator.frame())
149         return false;
150 
151     Page* page = navigator.frame()->page();
152     if (!page)
153         return false;
154 
155     if (page->visibilityState() != PageVisibilityStateVisible)
156         return false;
157 
158     return NavigatorVibration::from(*page).vibrate(pattern);
159 }
160 
from(Page & page)161 NavigatorVibration& NavigatorVibration::from(Page& page)
162 {
163     NavigatorVibration* navigatorVibration = static_cast<NavigatorVibration*>(WillBeHeapSupplement<Page>::from(page, supplementName()));
164     if (!navigatorVibration) {
165         navigatorVibration = new NavigatorVibration(page);
166         WillBeHeapSupplement<Page>::provideTo(page, supplementName(), adoptPtrWillBeNoop(navigatorVibration));
167     }
168     return *navigatorVibration;
169 }
170 
supplementName()171 const char* NavigatorVibration::supplementName()
172 {
173     return "NavigatorVibration";
174 }
175 
176 } // namespace blink
177