/* ============================================================================== This file is part of the JUCE library. Copyright (c) 2017 - ROLI Ltd. JUCE is an open source library subject to commercial or open-source licensing. By using JUCE, you agree to the terms of both the JUCE 5 End-User License Agreement and JUCE 5 Privacy Policy (both updated and effective as of the 27th April 2017). End User License Agreement: www.juce.com/juce-5-licence Privacy Policy: www.juce.com/juce-5-privacy-policy Or: You may also use this code under the terms of the GPL v3 (see www.gnu.org/licenses). JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE DISCLAIMED. ============================================================================== */ namespace juce { /* ============================================================================== In accordance with the terms of the JUCE 5 End-Use License Agreement, the JUCE Code in SECTION A cannot be removed, changed or otherwise rendered ineffective unless you have a JUCE Indie or Pro license, or are using JUCE under the GPL v3 license. End User License Agreement: www.juce.com/juce-5-licence ============================================================================== */ // BEGIN SECTION A #if ! defined (JUCE_REPORT_APP_USAGE) #define JUCE_REPORT_APP_USAGE 1 #endif #if ! defined (JUCE_DISPLAY_SPLASH_SCREEN) #define JUCE_DISPLAY_SPLASH_SCREEN 1 #endif #if ! defined (JUCE_USE_DARK_SPLASH_SCREEN) #define JUCE_USE_DARK_SPLASH_SCREEN 1 #endif static const int millisecondsToDisplaySplash = 2000, splashScreenFadeOutTime = 2000; static const int splashScreenLogoWidth = 123, splashScreenLogoHeight = 63; static uint32 splashDisplayTime = 0; static bool appUsageReported = false; static Rectangle getLogoArea (Rectangle parentRect) { return parentRect.reduced (6.0f) .removeFromRight ((float) splashScreenLogoWidth) .removeFromBottom ((float) splashScreenLogoHeight); } //============================================================================== struct ReportingThread; struct ReportingThreadContainer : public ChangeListener, public DeletedAtShutdown { ReportingThreadContainer() {} ~ReportingThreadContainer() override { clearSingletonInstance(); } void sendReport (String, String&, StringPairArray&); void changeListenerCallback (ChangeBroadcaster*) override; std::unique_ptr reportingThread; JUCE_DECLARE_SINGLETON_SINGLETHREADED_MINIMAL (ReportingThreadContainer) }; JUCE_IMPLEMENT_SINGLETON (ReportingThreadContainer) //============================================================================== struct ReportingThread : public Thread, private ChangeBroadcaster { ReportingThread (ReportingThreadContainer& container, String& address, String& userAgent, StringPairArray& parameters) : Thread ("JUCE app usage reporting"), threadContainer (container), headers ("User-Agent: " + userAgent) { StringArray postData; for (auto& key : parameters.getAllKeys()) if (parameters[key].isNotEmpty()) postData.add (key + "=" + URL::addEscapeChars (parameters[key], true)); url = URL (address).withPOSTData (postData.joinIntoString ("&")); addChangeListener (&threadContainer); } ~ReportingThread() override { removeChangeListener (&threadContainer); if (webStream != nullptr) webStream->cancel(); stopThread (2000); } void run() override { webStream.reset (new WebInputStream (url, true)); webStream->withExtraHeaders (headers); webStream->connect (nullptr); sendChangeMessage(); } private: ReportingThreadContainer& threadContainer; URL url; String headers; std::unique_ptr webStream; }; //============================================================================== void ReportingThreadContainer::sendReport (String address, String& userAgent, StringPairArray& parameters) { reportingThread.reset (new ReportingThread (*this, address, userAgent, parameters)); reportingThread->startThread(); } void ReportingThreadContainer::changeListenerCallback (ChangeBroadcaster*) { reportingThread.reset(); } //============================================================================== JUCESplashScreen::JUCESplashScreen (Component& parent) { ignoreUnused (hasStartedFading); ignoreUnused (parent); #if JUCE_REPORT_APP_USAGE if (! appUsageReported) { const ScopedTryLock appUsageReportingLock (appUsageReporting); if (appUsageReportingLock.isLocked() && ! appUsageReported) { const auto deviceDescription = SystemStats::getDeviceDescription(); const auto deviceString = SystemStats::getDeviceIdentifiers().joinIntoString (":"); const auto deviceIdentifier = String::toHexString (deviceString.hashCode64()); const auto osName = SystemStats::getOperatingSystemName(); StringPairArray data; data.set ("v", "1"); data.set ("tid", "UA-19759318-3"); data.set ("cid", deviceIdentifier); data.set ("t", "event"); data.set ("ec", "info"); data.set ("ea", "appStarted"); data.set ("cd1", SystemStats::getJUCEVersion()); data.set ("cd2", osName); data.set ("cd3", deviceDescription); data.set ("cd4", deviceIdentifier); String appType, appName, appVersion, appManufacturer; #if defined(JucePlugin_Name) appType = "Plugin"; appName = JucePlugin_Name; appVersion = JucePlugin_VersionString; appManufacturer = JucePlugin_Manufacturer; #else if (JUCEApplicationBase::isStandaloneApp()) { appType = "Application"; if (auto* app = JUCEApplicationBase::getInstance()) { appName = app->getApplicationName(); appVersion = app->getApplicationVersion(); } } else { appType = "Library"; } #endif data.set ("cd5", appType); data.set ("cd6", appName); data.set ("cd7", appVersion); data.set ("cd8", appManufacturer); data.set ("an", appName); data.set ("av", appVersion); auto agentCPUVendor = SystemStats::getCpuVendor(); if (agentCPUVendor.isEmpty()) agentCPUVendor = "CPU"; auto agentOSName = osName.replaceCharacter ('.', '_') .replace ("iOS", "iPhone OS"); #if JUCE_IOS agentOSName << " like Mac OS X"; #endif String userAgent; userAgent << "Mozilla/5.0 (" << deviceDescription << ";" << agentCPUVendor << " " << agentOSName << ";" << SystemStats::getDisplayLanguage() << ")"; ReportingThreadContainer::getInstance()->sendReport ("https://www.google-analytics.com/collect", userAgent, data); appUsageReported = true; } } #else ignoreUnused (appUsageReported); #endif #if JUCE_DISPLAY_SPLASH_SCREEN if (splashDisplayTime == 0 || Time::getMillisecondCounter() < splashDisplayTime + (uint32) millisecondsToDisplaySplash) { content = getSplashScreenLogo(); setAlwaysOnTop (true); parent.addAndMakeVisible (this); } else #endif { startTimer (1); } } JUCESplashScreen::~JUCESplashScreen() { } std::unique_ptr JUCESplashScreen::getSplashScreenLogo() { const char* svgData = R"JUCESPLASHSCREEN( " R"JUCESPLASHSCREEN( )JUCESPLASHSCREEN"; auto svgXml = parseXML (svgData); jassert (svgXml != nullptr); return std::unique_ptr (Drawable::createFromSVG (*svgXml)); } void JUCESplashScreen::paint (Graphics& g) { auto r = getLocalBounds().toFloat(); Point bottomRight (0.9f * r.getWidth(), 0.9f * r.getHeight()); ColourGradient cg (Colour (0x00000000), Line (0.0f, r.getHeight(), r.getWidth(), 0.0f) .findNearestPointTo (bottomRight), Colour (0xff000000), bottomRight, false); cg.addColour (0.25f, Colour (0x10000000)); cg.addColour (0.50f, Colour (0x30000000)); cg.addColour (0.75f, Colour (0x70000000)); g.setFillType (cg); g.fillAll(); content->drawWithin (g, getLogoArea (r), RectanglePlacement::centred, 1.0f); if (splashDisplayTime == 0) splashDisplayTime = Time::getMillisecondCounter(); if (! isTimerRunning()) startTimer (millisecondsToDisplaySplash); } void JUCESplashScreen::timerCallback() { #if JUCE_DISPLAY_SPLASH_SCREEN if (isVisible() && ! hasStartedFading) { hasStartedFading = true; fader.animateComponent (this, getBounds(), 0.0f, splashScreenFadeOutTime, false, 0, 0); } if (hasStartedFading && ! fader.isAnimating()) #endif delete this; } void JUCESplashScreen::parentSizeChanged() { if (auto* p = getParentComponent()) setBounds (p->getLocalBounds().removeFromBottom (splashScreenLogoHeight * 3) .removeFromRight (splashScreenLogoWidth * 3)); } void JUCESplashScreen::parentHierarchyChanged() { toFront (false); } bool JUCESplashScreen::hitTest (int x, int y) { if (! hasStartedFading) return getLogoArea (getLocalBounds().toFloat()).contains ((float) x, (float) y); return false; } void JUCESplashScreen::mouseUp (const MouseEvent&) { URL juceWebsite ("https://juce.com"); juceWebsite.launchInDefaultBrowser(); } // END SECTION A } // namespace juce