Home | History | Annotate | Download | only in vibration
      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