/* ============================================================================== This file is part of the JUCE 6 technical preview. Copyright (c) 2017 - ROLI Ltd. You may use this code under the terms of the GPL v3 (see www.gnu.org/licenses). For this technical preview, this file is not subject to commercial licensing. 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 splashHasStartedFading = false, 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 (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 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() && ! splashHasStartedFading) { splashHasStartedFading = true; fader.animateComponent (this, getBounds(), 0.0f, splashScreenFadeOutTime, false, 0, 0); } if (splashHasStartedFading && ! 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 (! splashHasStartedFading) 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