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 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 42 NavigatorVibration::~NavigatorVibration() 43 { 44 if (m_isVibrating) 45 cancelVibration(); 46 } 47 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 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 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 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 126 void NavigatorVibration::pageVisibilityChanged() 127 { 128 if (page()->visibilityState() != PageVisibilityStateVisible) 129 cancelVibration(); 130 } 131 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 139 bool NavigatorVibration::vibrate(Navigator& navigator, unsigned time) 140 { 141 VibrationPattern pattern; 142 pattern.append(time); 143 return NavigatorVibration::vibrate(navigator, pattern); 144 } 145 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 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 171 const char* NavigatorVibration::supplementName() 172 { 173 return "NavigatorVibration"; 174 } 175 176 } // namespace blink 177