Error:(120) error: unknown element <action> found.

博客介绍了Android studio中出现‘Error: unknown element found’错误的解决方法,即在gradle.properties文件中添加相关内容,还给出了参考博客链接。

       

使用环境: 

Error:(27) error: unknown element <category> found.
Error:(27) unknown element <category> found.
Error:java.util.concurrent.ExecutionException: java.util.concurrent.ExecutionException: com.android.tools.aapt2.Aapt2Exception: AAPT2 error: check logs for details
Error:java.util.concurrent.ExecutionException: com.android.tools.aapt2.Aapt2Exception: AAPT2 error: check logs for details
Error:com.android.tools.aapt2.Aapt2Exception: AAPT2 error: check logs for details
Error:Execution failed for task ':app:processDebugResources'.
> Failed to execute aapt
Information:BUILD FAILED in 10s

解决方法:

  在gradle.properties文件中添加:

android.enableAapt2=false

感谢 https://blog.youkuaiyun.com/springxudq/article/details/79169678 

感谢分享,谢谢。

<?xml version="1.0" encoding="utf-8"?> <resources> <string name="error__6">Operation failed. Please try later.</string> <string name="error_263">No default tenant found, please contact service provider.</string> <string name="error__107">Failed to connect to the camera. Try again later.</string> <string name="error_004">Invalid email address.</string> <string name="error_006">Incorrect mobile number.</string> <string name="error_009">The phone number has already been registered once, please use another number or use this number to login.</string> <string name="error_010">Incorrect verification code.</string> <string name="error_011">The email address has been bound.</string> <string name="error_012">Failed to log in to the app. Please log in again.</string> <string name="error_018">Invalid application ID.</string> <string name="error_019">Invalid operation.</string> <string name="error_024">Invalid plug-in.</string> <string name="error_025">Operation failed. Please try later.</string> <string name="error_026">Plug-in does not exist.</string> <string name="error_027">Failed to log in to the app. Please log in again.</string> <string name="error_030">The terminal has been bound.</string> <string name="error_031">Operation failed. Please try later.</string> <string name="error_032">The terminal does not bind to this account.</string> <string name="error_033">Terminals are being operated by other users.</string> <string name="error_034">Operation failed. Please try later.</string> <string name="error_035">Failed to obtain the application list.</string> <string name="error_036">Failed to obtain the application image.</string> <string name="error_037">Failed to obtain the application version.</string> <string name="error_038">Failed to obtain the Wi-Fi coverage information.</string> <string name="error_040">The email address has not been bound to an account.</string> <string name="error_042">Operation failed. Please try later.</string> <string name="error_044">Operation failed. Please try later.</string> <string name="error_048">Operation failed. Please try later.</string> <string name="error_050">Operation failed. Please try later.</string> <string name="error_051">Operation failed. Please try later.</string> <string name="error_056">Configuration page query failed.</string> <string name="error_057">Operation failed. Please try later.</string> <string name="error_058">Plug-in list query failed.</string> <string name="error_059">Plug-in image query failed.</string> <string name="error_060">Operation failed. Please try later.</string> <string name="error_061">Operation failed. Please try later.</string> <string name="error_063">Invalid broadband account.</string> <string name="error_064">Operation failed. Please try later.</string> <string name="error_066">Invalid account type.</string> <string name="error_067">The password cannot be empty.</string> <string name="error_068">The confirmation password cannot be empty.</string> <string name="error_069">The account cannot be empty.</string> <string name="error_070">Incorrect PPPoE account.</string> <string name="error_072">The cloud account is empty.</string> <string name="error_073">Incorrect cloud account type.</string> <string name="error_075">The cloud account is registered.</string> <string name="error_076">The cloud account does not exist.</string> <string name="error_077">You have not bound any broadband account or gateway.</string> <string name="error_078">The MAC address of the device is not registered to the cloud platform. </string> <string name="error_081">The current binding relationship does not exist.</string> <string name="error_082">The user account does not exist.</string> <string name="error_087">Binding failed, No broadband account.</string> <string name="error_093">You have not bound any broadband account.</string> <string name="error_094">The number of gateways to be bound has reached the maximum. New gateways cannot be bound.</string> <string name="error_097">Broadband account verification is not currently available.</string> <string name="error_098">The device already exists.</string> <string name="error_099">The Wi-Fi SSID already exists.</string> <string name="error_100">The Wi-Fi SSID is empty.</string> <string name="error_101">The account is added.</string> <string name="error_103">The password will expire soon.</string> <string name="error_105">The user account is locked.</string> <string name="error_106">User login failed.</string> <string name="error_107">Exceeded the number limit of accounts that can be logged in at the same time.</string> <string name="error_108">Password complexity is invalid.</string> <string name="error_110">Incorrect mobile phone type.</string> <string name="error_111">The mobile phone version is empty.</string> <string name="error_112">Exceeded the password resetting limit in 24 hours.</string> <string name="error_113">Exceeded the number limit of security question attempts. The password resetting is locked.</string> <string name="error_114">Incorrect answer to the security question.</string> <string name="error_115">Invalid parameter for the security question.</string> <string name="error_116">Incorrect old password.</string> <string name="error_117">No plug-in version.</string> <string name="error_118">Incorrect password.</string> <string name="error_121">Invalid order number.</string> <string name="error_122">WO cloud account has been registered.</string> <string name="error_123">WO cloud account does not exist.</string> <string name="error_124">WO cloud client authentication failed.</string> <string name="error_133">Failed to join.</string> <string name="error_139">Only administrators have this permission.</string> <string name="error_144">The log file size exceeds 5 MB and cannot be uploaded.</string> <string name="error_145">Plug-in already exists.</string> <string name="error_146">Plug-in version already exists.</string> <string name="error_150">The log switch has been enabled.</string> <string name="error_151">The log switch has been disabled.</string> <string name="error_152">Failed to query third-party authentication information.</string> <string name="error_153">Failed to forward plug-in third-party authentication information.</string> <string name="error_154">Duplicate room name.</string> <string name="error_155">The message template cannot be left empty.</string> <string name="error_156">The message template does not exist.</string> <string name="error_157">The mapping SMS template does not exist.</string> <string name="error_158">The SMS gateway is unavailable.</string> <string name="error_159">The plug-in service name is left empty or does not exist.</string> <string name="error_160">The plug-in service code is left empty or does not exist.</string> <string name="error_161">The plug-in random code is left blank or does not exist.</string> <string name="error_162">The mobile number cannot be left empty.</string> <string name="error_163">Failed to connect to the SMS gateway.</string> <string name="error_164">Failed to bind the SMS gateway.</string> <string name="error_165">Failed to send the SMS message.</string> <string name="error_166">SMS sending timed out.</string> <string name="error_171">The email address for receiving an authentication code is not the email address of the administrator.</string> <string name="error_172">The format of the message notification switch is incorrect.</string> <string name="error_173">The user password of the storage service fails the verification.</string> <string name="error_174">Status of the gateway to which the user is bound is invalid.</string> <string name="error_175">The email server is not configured.</string> <string name="error_176">Failed to send the email.</string> <string name="error_184">Sender authentication on the email server failed.</string> <string name="error_185">Incorrect email address.</string> <string name="error_186">Operation failed. Please try later.</string> <string name="error_187">Operation failed. Please try later.</string> <string name="error_189">You do not have the permission to access the gateway.</string> <string name="error_192">This type of message is not currently supported by the SMS gateway.</string> <string name="error_193">Sessiontimeout must be specified if the speed-up interface oper_type is set to 0.</string> <string name="error_196">Image size too large.</string> <string name="error_197">Incorrect image format.</string> <string name="error_198">The plug-in software version is not available.</string> <string name="error_199">Mandatory parameter symbolicName not found.</string> <string name="error_200">The plug-in record is empty.</string> <string name="error_204">BSS is not configured.</string> <string name="error_205">Failed to register the cloud account.</string> <string name="error_209">Mandatory parameter #{field} is not carried or is left empty.</string> <string name="error_210">Invalid request format.</string> <string name="error_211">The password has expired.</string> <string name="error_212">The user is blocked.</string> <string name="error_213">The MAC address is not bound.</string> <string name="error_215">You have not purchased such type of device.</string> <string name="error_216">Failed to identify the device type.</string> <string name="error_217">The number of devices of this type exceeds the maximum allowed by the package.</string> <string name="error_218">The package has not been activated.</string> <string name="error_222">Cloud storage has not been configured on the web page.</string> <string name="error_226">The account is not bound to a mobile number.</string> <string name="error_227">The account is not bound to an email address.</string> <string name="error_228">The cloud storage parameters cannot be left empty.</string> <string name="error_230">Failed to create the temporary Amazon Cloud certificate.</string> <string name="error_231">The verification code has expired.</string> <string name="error_232">No profile image has been uploaded for the user.</string> <string name="error_233">The application has not been purchased.</string> <string name="error_234">Incorrect cloud storage configuration.</string> <string name="error_236">Failed to obtain the cloud token.</string> <string name="error_237">Non-current administrator to create sub-accounts</string> <string name="error_244">The mobile number cannot be used for login.</string> <string name="error_245">The email address cannot be used for login.</string> <string name="error_246">The account cannot be modified repeatedly.</string> <string name="error_248">The plug-in is the latest version.</string> <string name="error_249">The login has expired.</string> <string name="error_250">The plug-in is the latest version.</string> <string name="error_251">Users with no service provisioned cannot bind a gateway.</string> <string name="error_252">The mobile number bound to the new administrator does not match the number segment specified by the carrier.</string> <string name="error_253">The mobile phone number bound to the new administrator is not used.</string> <string name="error_254">The mobile phone number bound to the new administrator has been used.</string> <string name="error_256">Your account has been disabled.</string> <string name="error_1018">Your password has been reset, please set a new password on the cloud platform</string> <string name="error_30000001">Operation failed. Please try later.</string> <string name="error_30000101">The account already exists.</string> <string name="error_30000102">The account does not exist.</string> <string name="error_30000103">The new account already exists.</string> <string name="error_30000104">The mobile number already exists.</string> <string name="error_30000105">The email address already exists.</string> <string name="error_30000106">The package does not exist.</string> <string name="error_30000107">Product ID{#{field}} does not exist.</string> <string name="error_30000108">Incorrect email address format.</string> <string name="error_30000109">The password does not meet the complexity requirements. Enter a correct one.</string> <string name="error_30000110">The account is not an administrator account.</string> <string name="error_30000111">No gateway has been bound for the account.</string> <string name="error_30000112">Multiple gateways have been bound for the account.</string> <string name="error_30000113">The gateway bound to this account has been enabled for remote management.</string> <string name="error_30000114">The gateway bound to this account has suspended remote management</string> <string name="error_30000115">The package is not specified.</string> <string name="error_30000116">Failed to delete the storage service file.</string> <string name="error_30000121">Unknown northbound bundle operation.</string> <string name="error_30000122">The plug-in software version is not found.</string> <string name="error_30000123">The plug-in software version already exists.</string> <string name="error_30000124">Mandatory parameter symbolicName is not specified.</string> <string name="error_30000125">The plug-in record is empty.</string> <string name="error_30000126">The plug-in has been bound to an app.</string> <string name="error_30000127">The plug-in does not exist.</string> <string name="error_30000128">The format of the mobile number is incorrect.</string> <string name="error_30000129">A new account cannot be the same as the old account.</string> <string name="error_30000130">The password must be different from previous passwords.</string> <string name="error__1004">The service package is not available for use.</string> <string name="error__1008">The entered broadband account is inconsistent with the one used for dial-up access.</string> <string name="error__1011">The user is offline.</string> <string name="error__1012">Subscribed services have expired.</string> <string name="error__1014">The IP address is outside the IP address range that has access to smart speed-up.</string> <string name="error__1015">The remaining quota is zero.</string> <string name="error_2002">The room does not exist.</string> <string name="error_2003">The device SN does not exist.</string> <string name="error_2004">The device is already added.</string> <string name="error_2005">No such device service is purchased.</string> <string name="error_2006">The package is not activated.</string> <string name="error_2007">The number of devices exceeds the limit of package.</string> <string name="error_2008">The device name already exists.</string> <string name="error_10100502">The service is invalid.</string> <string name="error_10100503">The service has ceased.</string> <string name="error_10100505">The service package does not exist.</string> <string name="error_10100508">BOD services do not support accumulation.</string> <string name="error_10100509">No basic-bandwidth information is available to calculate the amount of additional BOD bandwidth required.</string> <string name="error_10100601">The service is not subscribed.</string> <string name="error_10100602">The service is in used.</string> <string name="error_10100604">The service is not in use and the acceleration does not need to be stopped.</string> <string name="error_999">Operation failed. Please try later.</string> <string name="error_999108">Operation failed. Please try later.</string> <string name="error_999100">Service cannot parse XML-request and detect necessary fields</string> <string name="error_999101">Account for requested login or contract number is not found (for methods like balance checking)</string> <string name="error_999102">The contract attachment of the requested number is not found.</string> <string name="error_999103">Service with the requested number is not found</string> <string name="error_999104">Wrong phone number format</string> <string name="error_999105">Wrong email format</string> <string name="error_999106">Password doesn\'t meet the requirements (too short, etc)</string> <string name="error_999107">Error of internal account identification</string> <string name="error_999200">Method is not supported or not currently available</string> <string name="error_999202">BSS returns an error indicating that changing the mobile phone number failed.</string> <string name="error_999203">BSS returns an error indicating that changing the email address failed.</string> <string name="error_999300">Error during internal request processing in billing system (it will be returned XML-structure with details of the error)</string> <string name="error_network_err">Connection timed out. Check your network connection.</string> <string name="error_40000002">The length exceeds the maximum limit.</string> <string name="error_40000005">The parameter value exceeds the maximum value.</string> <string name="error_40000006">The parameter value is less than the minimum value.</string> <string name="error_80010001">The scene name already exists.</string> <string name="error_80010002">The scene name is empty.</string> <string name="error_80010003">The scene contains non-existing or deleted devices.</string> <string name="error_80010004">The scene name does not exist.</string> <string name="error_80000001">The plug-in name is empty.</string> <string name="error_80000002">The data flag is empty.</string> <string name="error_80010005">The action of the device is empty.</string> <string name="error_80010006">The device type does not exist.</string> <string name="error_80011001">The app name does not exist.</string> <string name="error_80011002">The operation name is empty.</string> <string name="error_80011003">The service name does not exist.</string> <string name="error_80012001">The camera password is incorrect or locked.</string> <string name="error_80013001">More rooms are created than allowed.</string> <string name="error_80010007">Incorrect time format in the scheduled scene.</string> <string name="error_80010008">The action name is empty.</string> <string name="error_80010009">Name of trigger condition is empty.</string> <string name="error_1013">The MAC address of your gateway does not exist on the server.</string> <string name="logo_homeGatewayService.token.invalid">Your login has expired.</string> <string name="error_1014">The number of verification codes sent in your account has reached the maximum. Please try again tomorrow.</string> <string name="error_0x02163dc3">The number of same characters in a row in the password has exceeded the maximum.</string> <string name="error_0x02163dcc">Failed to input the correct old password.</string> <string name="error_0x02163dc1">The password does not meet requirements.</string> <string name="error_0x02163dc2">The length of the password does not meet requirements.</string> <string name="error_0x021639b8">The new password must contain at least two characters that are not used in the old password.</string> <string name="error_0x02163dc4">The password does not comply with the repetition policy.</string> <string name="error_0x02163dc6">The operation does not comply with the minimum modification time interval.</string> <string name="error_0035014004">Password entered incorrectly too many times, please wait %1$s minutes and try again.</string> <string name="error_276">The mobile number has been registered with another broadband service provider and cannot be invited.</string> <string name="error_across_tenant">The mobile number has been registered with another broadband service provider, so you cannot invite it.</string> <string name="error__11">Operation failed. Please try later.</string> <string name="error__12">Operation failed. Please try later.</string> <string name="error_HomeGatewayService_parameter_invalid">Incorrect request parameter.</string> <string name="error_HomeGatewayService_cmdtype_invalid">The current platform version does not support this function.</string> <string name="error_HomeGatewayService_service_invalid">Server error.</string> <string name="error_HomeGatewayService_homegateway_no_permission">You do not have permission to manage the gateway.</string> <string name="error_281">Failed to send the SMS message. Please contact your broadband service provider.</string> <string name="error_282">The server fails to send an SMS message because the mobile number is invalid.</string> <string name="error_283">The server fails to send an SMS message because the mobile number is invalid.</string> <string name="error_284">The server is busy sending SMS messages. Please try again later.</string> <string name="error_285">The server is busy sending SMS messages. Please try again later.</string> <string name="error_286">The server fails to send the SMS message because the content is invalid.</string> <string name="error_287">The server fails to send an SMS message because the number is in the blacklist.</string> <string name="error_288">The SMS message sent by the server contains sensitive words. Change your gateway remarks and try again.</string> <string name="error_0">Operation successful.</string> <string name="error_7">The gateway is busy and cannot process the current request. Try again later.</string> <string name="error__1">Operation failed. Please try later.</string> <string name="error__2">Network request timed out.</string> <string name="error__36">The Wi-Fi service has been disabled.</string> <string name="error__100">Failed to assign transit server port. Try again</string> <string name="error__101">Failed to connect to the transit server. Check if the server is online.</string> <string name="error__105">Failed to obtain the video service address of the camera</string> <string name="error__108">User authentication failed</string> <string name="error__202">When MLO is enabled, the authentication mode must be WPA2, WPA3, or WPA2/WPA3.</string> <string name="error_001">Duplicate username.</string> <string name="error_002">Passwords don’t match.</string> <string name="error_003">Incorrect username or password.</string> <string name="error_005">The length of the password does not meet requirements.</string> <string name="error_007">The username cannot be empty.</string> <string name="error_008">Duplicate nickname.</string> <string name="error_013">Incorrect username or password.</string> <string name="error_014">Exceeded the maximum number of terminals bound to the current account.</string> <string name="error_015">Exceeded the maximum number of accounts bound to this terminal.</string> <string name="error_016">No smart ONT has been bound</string> <string name="error_020">The gateway is offline.</string> <string name="error_021">You do not have the permission to access the gateway.</string> <string name="error_022">The gateway is not registered.</string> <string name="error_023">The username does not exist.</string> <string name="error_029">No terminal is bound to this account.</string> <string name="error_039">The mobile number has not been bound to an account.</string> <string name="error_041">Failed to modify the password: The old password is entered incorrectly.</string> <string name="error_043">The gateway connection timed out. Try again later or check whether the gateway network is connected.</string> <string name="error_045">Operation failed. Please try later.</string> <string name="error_046">Operation failed. Please try later.</string> <string name="error_047">Failed to obtain the device control list.</string> <string name="error_049">Exceeded the maximum number of controllable devices.</string> <string name="error_052">The gateway is not registered.</string> <string name="error_053">Device control is not supported.</string> <string name="error_054">Operation failed. Please try later.</string> <string name="error_055">Unknown error occurred on the device control template.</string> <string name="error_065">Problem description cannot be empty.</string> <string name="error_071">Not a smart gateway.</string> <string name="error_079">Operation failed: the gateway has been unbound.</string> <string name="error_080">Operation failed: the current account has not joined.</string> <string name="error_083">Operation failed. Please try later.</string> <string name="error_084">A non-invite user cannot modify the remarks.</string> <string name="error_085">Unbinding failed. Please try again later.</string> <string name="error_086">Devices exist in the room.</string> <string name="error_088">This app does not support non-smart gateways.</string> <string name="error_089">Binding failed. Please try again later.</string> <string name="error_090">Binding failed. Please try again later.</string> <string name="error_091">Binding failed. Please try again later.</string> <string name="error_092">The number of invited users has exceeded the upper limit.</string> <string name="error_095">Deletion failed. The last user cannot be deleted.</string> <string name="error_096">The list of network users to be deleted is empty.</string> <string name="error_102">The new password cannot be the same as any previous password.</string> <string name="error_104">The password has expired.</string> <string name="error_109">The greeting message is empty.</string> <string name="error_119">The room name cannot be empty.</string> <string name="error_120">The room ID cannot be empty.</string> <string name="error_125">The username does not meet the complexity requirements. Enter a correct one.</string> <string name="error_126">The username cannot be empty.</string> <string name="error_127">The username does not meet the complexity requirements. Enter a correct one.</string> <string name="error_128">No mobile number is bound.</string> <string name="error_129">This mobile number is not a administrator account.</string> <string name="error_130">The mobile number must be a Bahraini number.</string> <string name="error_131">The mobile number has been bound.</string> <string name="error_132">No phone number is bound to the current account.</string> <string name="error_134">Administrators cannot leave.</string> <string name="error_135">The mobile number is not bound to any account.</string> <string name="error_136">The login has expired.</string> <string name="error_140">The device has been updated to the latest version.</string> <string name="error_141">No new version is available.</string> <string name="error_143">Incorrect log file format.</string> <string name="error_147">The gateway is being upgraded.</string> <string name="error_148">The phone number has already been registered once, please use another number or use this number to login.</string> <string name="error_149">Duplicate room name.</string> <string name="error_167">Operation failed. Please try later.</string> <string name="error_168">Starting the plug-in…</string> <string name="error_169">Stopping the plug-in…</string> <string name="error_170">Uninstalling the plug-in…</string> <string name="error_188">The gateway does not exist.</string> <string name="error_190">You do not have access to this gateway.</string> <string name="error_191">The message push type is empty or of an incorrect format.</string> <string name="error_194">Operation failed. Please try later.</string> <string name="error_195">You cannot invite other network members to join.</string> <string name="error_LHConsumerService_login_accountRoleMismatch">Members from other enterprises are not allowed.</string> <string name="error_LHConsumerService_bindGroup_exceedMaxBindGroupNum">Members from other enterprises are not allowed.</string> <string name="error_201">Failed to check the remaining balance.</string> <string name="error_202">Failed to change the mobile number.</string> <string name="error_203">Failed to change the email address.</string> <string name="error_214">Incorrect addedDeviceList format.</string> <string name="error_219">The password cannot be the same as the username or the username in reverse.</string> <string name="error_220">You do not have the administrative permission.</string> <string name="error_221">Failed to uninstall all the plug-ins of the home gateway.</string> <string name="error_224">The new gateway is not registered.</string> <string name="error_225">The new home gateway has been bound.</string> <string name="error_238">Your account has not been bound with a mobile number or email address. The password cannot be retrieved through self service. You are advised to contact your administrator to retrieve the password.</string> <string name="error_239">The mobile number is bound to multiple accounts.</string> <string name="error_240">The email address is bound to multiple accounts.</string> <string name="error_247">Anonymous binding information cannot be queried by using a mobile number or an email address.</string> <string name="error_255">The account has been bound to a gateway, and cannot be bound to another one.</string> <string name="error_272">Incorrect username or password.</string> <string name="error_1002">The interval between requests for sending verification codes is too short.</string> <string name="error_30000117">The home gateway MAC address does not exist.</string> <string name="error_30000118">The home gateway is offline.</string> <string name="error_30000119">The home gateway plug-in does not exist.</string> <string name="error_30000120">The plug-in is not installed or not upgraded on the home gateway.</string> <string name="error__1013">The MAC address (XXX) of your gateway does not exist on the server.</string> <string name="error_2001">The input parameter is empty.</string> <string name="error_40000001">The parameter contains unsupported special characters.</string> <string name="error_40000003">The length is less than the minimum limit.</string> <string name="error_40000004">The parameter is not a numeric type.</string> <string name="error_40000007">Invalid IP address.</string> <string name="net_conn_failed">Connection failed.</string> <string name="error__3">Connection failed.</string> <string name="error__4">The gateway is busy and cannot process the current request. Try again later.</string> <string name="error__5">Operation failed. Please try later.</string> <string name="error__7">Operation failed. Please try later.</string> <string name="error__8">Not supported by the gateway.</string> <string name="error__9">Operation failed. Please try later.</string> <string name="error__10">Your login has expired. Please log in again.</string> <string name="error_280">Failed to send the SMS message. Please try again later.</string> <string name="error_300">The current server version does not support user name registration.</string> <string name="error__102">Camera offline or camera connection failed. Check if the camera is powered on.</string> <string name="error__104">Camera video service address illegal, please report impaired</string> <string name="error__106">Gateway cannot connect to the transit server. Check if the server is online.</string> <string name="error__200">Reached the upper limit.</string> <string name="error__201">When MLO is enabled, the working mode must be 802.11be.</string> <string name="error__203">Saving Wi-Fi settings. Please wait.</string> <string name="error__204">Incorrect request parameter.</string> <string name="error__205">The Wi-Fi frequency band is not enabled. Enable it first.</string> <string name="error__301">Fails to play the real-time video of the camera. Failed to connect to the gateway locally.</string> <string name="error__330">Application control is not enabled. Please enable it first.</string> <string name="error__331">The number of application control policies has reached the upper limit.</string> <string name="error__332">The app control rule does not exist.</string> <string name="error__622">The rate limit periods cannot overlap with each other.</string> <string name="error_028">Your account has been used for login on another device. If this was done without your knowledge, your account and password may have been compromised. Choose Settings > Account And Security to change your account password.</string> <string name="error_2009">Failed to query the package status.</string> <string name="error__99999">Operation failed. Please try later.</string> <string name="error_1017">The MAC address cannot be empty.</string> <string name="error_licence_expire">Licence expired, please contact service provider.</string> <string name="LHConsumerService.bindLocalAccount.hasFamily">The account is already in a family.</string> <string name="LHConsumerService.bindLocalAccount.bound">Already bound to another account.</string> <string name="LHConsumerService.weakvalue.error">The password is too simple.</string> <string name="error_LHConsumerService_feedback_daylimit">The number of problems you reported has reached the upper limit. Try again 24 hours later.</string> <string name="error_306">Failed to send the verification code.The possible cause is that the mobile number format is incorrect or the mobile number has been bound.</string> <string name="error_307">Failed to send the verification code.The possible cause is that the email address format is incorrect or the email address has been bound.</string> <string name="error_308">Failed to send the verification code.The possible cause is that the mobile number format is incorrect or the mobile number is not bound.</string> <string name="error_309">Failed to send the verification code.The possible cause is that the email address format is incorrect or the email address is not bound.</string> <string name="error_310">The client IP address is locked,please try again later.</string> <string name="error_311">The current version does not support multi-factor authentication. Contact the administrator to disable multi-factor authentication.</string> <string name="error__340">The portal function has been enabled. The speed limit cannot be configured. To set the rate limit, disable Portal authentication on the web management page of the gateway.</string> <string name="error_AppSdk_notInitialized">Failed to initialize the app. Please log in again.</string> <string name="error_log_collect_offline">Device is offline</string> <string name="error_log_collect_conflict">Another collection task of the device is in progress.</string> <string name="error_log_collect_failed">Log collection failed</string> <string name="LHConsumerService.domainMigration.notSupportBinding">The server has been switched. Please switch to the corresponding region and register again.</string> <string name="error__41">Failed to set the 5G Wi-Fi because it has been locked. Contact your carrier to enable it first.</string> <string name="error__14">The same Wi-Fi SSID already exists in the current frequency band.</string> <string name="BindGateway_101">You have joined a family. Please refresh the home page and view it.</string> <string name="error_third_platform_user">Third-party users exist, unbinding failed.</string> </resources>
06-11
> Task :app:processDebugMainManifest FAILED package="com.example.datiqiapp" found in source AndroidManifest.xml: G:\dati\app\src\main\AndroidManifest.xml. Setting the namespace via the package attribute in the source AndroidManifest.xml is no longer supported, and the value is ignored. Recommendation: remove package="com.example.datiqiapp" from the source AndroidManifest.xml: G:\dati\app\src\main\AndroidManifest.xml. G:\dati\app\src\main\AndroidManifest.xml:13:9-19:20 Error: android:exported needs to be explicitly specified for element <activity#com.example.datiqiapp.UI.DaohangActivity>. Apps targeting Android 12 and higher are required to specify an explicit value for `android:exported` when the corresponding component has an intent filter defined. See https://developer.android.com/guide/topics/manifest/activity-element#exported for details. See https://developer.android.com/r/studio-ui/build/manifest-merger for more information about the manifest merger. Execution failed for task ':app:processDebugMainManifest'. > Manifest merger failed : android:exported needs to be explicitly specified for element <activity#com.example.datiqiapp.UI.DaohangActivity>. Apps targeting Android 12 and higher are required to specify an explicit value for `android:exported` when the corresponding component has an intent filter defined. See https://developer.android.com/guide/topics/manifest/activity-element#exported for details. * Try: > Run with --info or --debug option to get more log output. > Run with --scan to get full insights. > Get more help at https://help.gradle.org. * Exception is: org.gradle.api.tasks.TaskExecutionException: Execution failed for task ':app:processDebugMainManifest'. at org.gradle.api.internal.tasks.execution.ExecuteActionsTaskExecuter.lambda$executeIfValid$1(ExecuteActionsTaskExecuter.java:130) at org.gradle.internal.Try$Failure.ifSuccessfulOrElse(Try.java:282) at org.gradle.api.internal.tasks.execution.ExecuteActionsTaskExecuter.executeIfValid(ExecuteActionsTaskExecuter.java:128) at org.gradle.api.internal.tasks.execution.ExecuteActionsTaskExecuter.execute(ExecuteActionsTaskExecuter.java:116) at org.gradle.api.internal.tasks.execution.FinalizePropertiesTaskExecuter.execute(FinalizePropertiesTaskExecuter.java:46) at org.gradle.api.internal.tasks.execution.ResolveTaskExecutionModeExecuter.execute(ResolveTaskExecutionModeExecuter.java:51) at org.gradle.api.internal.tasks.execution.SkipTaskWithNoActionsExecuter.execute(SkipTaskWithNoActionsExecuter.java:57) at org.gradle.api.internal.tasks.execution.SkipOnlyIfTaskExecuter.execute(SkipOnlyIfTaskExecuter.java:74) at org.gradle.api.internal.tasks.execution.CatchExceptionTaskExecuter.execute(CatchExceptionTaskExecuter.java:36) at org.gradle.api.internal.tasks.execution.EventFiringTaskExecuter$1.executeTask(EventFiringTaskExecuter.java:77) at org.gradle.api.internal.tasks.execution.EventFiringTaskExecuter$1.call(EventFiringTaskExecuter.java:55) at org.gradle.api.internal.tasks.execution.EventFiringTaskExecuter$1.call(EventFiringTaskExecuter.java:52) at org.gradle.internal.operations.DefaultBuildOperationRunner$CallableBuildOperationWorker.execute(DefaultBuildOperationRunner.java:200) at org.gradle.internal.operations.DefaultBuildOperationRunner$CallableBuildOperationWorker.execute(DefaultBuildOperationRunner.java:195) at org.gradle.internal.operations.DefaultBuildOperationRunner$2.execute(DefaultBuildOperationRunner.java:66) at org.gradle.internal.operations.DefaultBuildOperationRunner$2.execute(DefaultBuildOperationRunner.java:59) at org.gradle.internal.operations.DefaultBuildOperationRunner.execute(DefaultBuildOperationRunner.java:157) at org.gradle.internal.operations.DefaultBuildOperationRunner.execute(DefaultBuildOperationRunner.java:59) at org.gradle.internal.operations.DefaultBuildOperationRunner.call(DefaultBuildOperationRunner.java:53) at org.gradle.internal.operations.DefaultBuildOperationExecutor.call(DefaultBuildOperationExecutor.java:73) at org.gradle.api.internal.tasks.execution.EventFiringTaskExecuter.execute(EventFiringTaskExecuter.java:52) at org.gradle.execution.plan.LocalTaskNodeExecutor.execute(LocalTaskNodeExecutor.java:42) at org.gradle.execution.taskgraph.DefaultTaskExecutionGraph$InvokeNodeExecutorsAction.execute(DefaultTaskExecutionGraph.java:331) at org.gradle.execution.taskgraph.DefaultTaskExecutionGraph$InvokeNodeExecutorsAction.execute(DefaultTaskExecutionGraph.java:318) at org.gradle.execution.taskgraph.DefaultTaskExecutionGraph$BuildOperationAwareExecutionAction.lambda$execute$0(DefaultTaskExecutionGraph.java:314) at org.gradle.internal.operations.CurrentBuildOperationRef.with(CurrentBuildOperationRef.java:80) at org.gradle.execution.taskgraph.DefaultTaskExecutionGraph$BuildOperationAwareExecutionAction.execute(DefaultTaskExecutionGraph.java:314) at org.gradle.execution.taskgraph.DefaultTaskExecutionGraph$BuildOperationAwareExecutionAction.execute(DefaultTaskExecutionGraph.java:303) at org.gradle.execution.plan.DefaultPlanExecutor$ExecutorWorker.execute(DefaultPlanExecutor.java:463) at org.gradle.execution.plan.DefaultPlanExecutor$ExecutorWorker.run(DefaultPlanExecutor.java:380) at org.gradle.internal.concurrent.ExecutorPolicy$CatchAndRecordFailures.onExecute(ExecutorPolicy.java:64) at org.gradle.internal.concurrent.AbstractManagedExecutor$1.run(AbstractManagedExecutor.java:47) Caused by: java.lang.RuntimeException: Manifest merger failed : android:exported needs to be explicitly specified for element <activity#com.example.datiqiapp.UI.DaohangActivity>. Apps targeting Android 12 and higher are required to specify an explicit value for `android:exported` when the corresponding component has an intent filter defined. See https://developer.android.com/guide/topics/manifest/activity-element#exported for details. at com.android.build.gradle.internal.tasks.manifest.ManifestHelperKt.mergeManifests(ManifestHelper.kt:125) at com.android.build.gradle.internal.tasks.manifest.ManifestHelperKt.mergeManifests$default(ManifestHelper.kt:46) at com.android.build.gradle.tasks.ProcessApplicationManifest.doTaskAction(ProcessApplicationManifest.kt:163) at com.android.build.gradle.internal.tasks.NonIncrementalTask$taskAction$$inlined$recordTaskAction$1.invoke(BaseTask.kt:66) at com.android.build.gradle.internal.tasks.Blocks.recordSpan(Blocks.java:51) at com.android.build.gradle.internal.tasks.NonIncrementalTask.taskAction(NonIncrementalTask.kt:97) at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(Unknown Source) at org.gradle.internal.reflect.JavaMethod.invoke(JavaMethod.java:125) at org.gradle.api.internal.project.taskfactory.StandardTaskAction.doExecute(StandardTaskAction.java:58) at org.gradle.api.internal.project.taskfactory.StandardTaskAction.execute(StandardTaskAction.java:51) at org.gradle.api.internal.project.taskfactory.StandardTaskAction.execute(StandardTaskAction.java:29) at org.gradle.api.internal.tasks.execution.TaskExecution$3.run(TaskExecution.java:244) at org.gradle.internal.operations.DefaultBuildOperationRunner$1.execute(DefaultBuildOperationRunner.java:29) at org.gradle.internal.operations.DefaultBuildOperationRunner$1.execute(DefaultBuildOperationRunner.java:26) at org.gradle.internal.operations.DefaultBuildOperationRunner$2.execute(DefaultBuildOperationRunner.java:66) at org.gradle.internal.operations.DefaultBuildOperationRunner$2.execute(DefaultBuildOperationRunner.java:59) at org.gradle.internal.operations.DefaultBuildOperationRunner.execute(DefaultBuildOperationRunner.java:157) at org.gradle.internal.operations.DefaultBuildOperationRunner.execute(DefaultBuildOperationRunner.java:59) at org.gradle.internal.operations.DefaultBuildOperationRunner.run(DefaultBuildOperationRunner.java:47) at org.gradle.internal.operations.DefaultBuildOperationExecutor.run(DefaultBuildOperationExecutor.java:68) at org.gradle.api.internal.tasks.execution.TaskExecution.executeAction(TaskExecution.java:229) at org.gradle.api.internal.tasks.execution.TaskExecution.executeActions(TaskExecution.java:212) at org.gradle.api.internal.tasks.execution.TaskExecution.executeWithPreviousOutputFiles(TaskExecution.java:195) at org.gradle.api.internal.tasks.execution.TaskExecution.execute(TaskExecution.java:162) at org.gradle.internal.execution.steps.ExecuteStep.executeInternal(ExecuteStep.java:105) at org.gradle.internal.execution.steps.ExecuteStep.access$000(ExecuteStep.java:44) at org.gradle.internal.execution.steps.ExecuteStep$1.call(ExecuteStep.java:59) at org.gradle.internal.execution.steps.ExecuteStep$1.call(ExecuteStep.java:56) at org.gradle.internal.operations.DefaultBuildOperationRunner$CallableBuildOperationWorker.execute(DefaultBuildOperationRunner.java:200) at org.gradle.internal.operations.DefaultBuildOperationRunner$CallableBuildOperationWorker.execute(DefaultBuildOperationRunner.java:195) at org.gradle.internal.operations.DefaultBuildOperationRunner$2.execute(DefaultBuildOperationRunner.java:66) at org.gradle.internal.operations.DefaultBuildOperationRunner$2.execute(DefaultBuildOperationRunner.java:59) at org.gradle.internal.operations.DefaultBuildOperationRunner.execute(DefaultBuildOperationRunner.java:157) at org.gradle.internal.operations.DefaultBuildOperationRunner.execute(DefaultBuildOperationRunner.java:59) at org.gradle.internal.operations.DefaultBuildOperationRunner.call(DefaultBuildOperationRunner.java:53) at org.gradle.internal.operations.DefaultBuildOperationExecutor.call(DefaultBuildOperationExecutor.java:73) at org.gradle.internal.execution.steps.ExecuteStep.execute(ExecuteStep.java:56) at org.gradle.internal.execution.steps.ExecuteStep.execute(ExecuteStep.java:44) at org.gradle.internal.execution.steps.CancelExecutionStep.execute(CancelExecutionStep.java:41) at org.gradle.internal.execution.steps.TimeoutStep.executeWithoutTimeout(TimeoutStep.java:74) at org.gradle.internal.execution.steps.TimeoutStep.execute(TimeoutStep.java:55) at org.gradle.internal.execution.steps.PreCreateOutputParentsStep.execute(PreCreateOutputParentsStep.java:50) at org.gradle.internal.execution.steps.PreCreateOutputParentsStep.execute(PreCreateOutputParentsStep.java:28) at org.gradle.internal.execution.steps.RemovePreviousOutputsStep.execute(RemovePreviousOutputsStep.java:67) at org.gradle.internal.execution.steps.RemovePreviousOutputsStep.execute(RemovePreviousOutputsStep.java:37) at org.gradle.internal.execution.steps.BroadcastChangingOutputsStep.execute(BroadcastChangingOutputsStep.java:61) at org.gradle.internal.execution.steps.BroadcastChangingOutputsStep.execute(BroadcastChangingOutputsStep.java:26) at org.gradle.internal.execution.steps.CaptureOutputsAfterExecutionStep.execute(CaptureOutputsAfterExecutionStep.java:67) at org.gradle.internal.execution.steps.CaptureOutputsAfterExecutionStep.execute(CaptureOutputsAfterExecutionStep.java:45) at org.gradle.internal.execution.steps.ResolveInputChangesStep.execute(ResolveInputChangesStep.java:40) at org.gradle.internal.execution.steps.ResolveInputChangesStep.execute(ResolveInputChangesStep.java:29) at org.gradle.internal.execution.steps.BuildCacheStep.executeWithoutCache(BuildCacheStep.java:189) at org.gradle.internal.execution.steps.BuildCacheStep.lambda$execute$1(BuildCacheStep.java:75) at org.gradle.internal.Either$Right.fold(Either.java:175) at org.gradle.internal.execution.caching.CachingState.fold(CachingState.java:62) at org.gradle.internal.execution.steps.BuildCacheStep.execute(BuildCacheStep.java:73) at org.gradle.internal.execution.steps.BuildCacheStep.execute(BuildCacheStep.java:48) at org.gradle.internal.execution.steps.StoreExecutionStateStep.execute(StoreExecutionStateStep.java:46) at org.gradle.internal.execution.steps.StoreExecutionStateStep.execute(StoreExecutionStateStep.java:35) at org.gradle.internal.execution.steps.SkipUpToDateStep.executeBecause(SkipUpToDateStep.java:76) at org.gradle.internal.execution.steps.SkipUpToDateStep.lambda$execute$2(SkipUpToDateStep.java:54) at org.gradle.internal.execution.steps.SkipUpToDateStep.execute(SkipUpToDateStep.java:54) at org.gradle.internal.execution.steps.SkipUpToDateStep.execute(SkipUpToDateStep.java:36) at org.gradle.internal.execution.steps.legacy.MarkSnapshottingInputsFinishedStep.execute(MarkSnapshottingInputsFinishedStep.java:37) at org.gradle.internal.execution.steps.legacy.MarkSnapshottingInputsFinishedStep.execute(MarkSnapshottingInputsFinishedStep.java:27) at org.gradle.internal.execution.steps.ResolveIncrementalCachingStateStep.executeDelegate(ResolveIncrementalCachingStateStep.java:49) at org.gradle.internal.execution.steps.ResolveIncrementalCachingStateStep.executeDelegate(ResolveIncrementalCachingStateStep.java:27) at org.gradle.internal.execution.steps.AbstractResolveCachingStateStep.execute(AbstractResolveCachingStateStep.java:71) at org.gradle.internal.execution.steps.AbstractResolveCachingStateStep.execute(AbstractResolveCachingStateStep.java:39) at org.gradle.internal.execution.steps.ResolveChangesStep.execute(ResolveChangesStep.java:65) at org.gradle.internal.execution.steps.ResolveChangesStep.execute(ResolveChangesStep.java:36) at org.gradle.internal.execution.steps.ValidateStep.execute(ValidateStep.java:106) at org.gradle.internal.execution.steps.ValidateStep.execute(ValidateStep.java:55) at org.gradle.internal.execution.steps.AbstractCaptureStateBeforeExecutionStep.execute(AbstractCaptureStateBeforeExecutionStep.java:64) at org.gradle.internal.execution.steps.AbstractCaptureStateBeforeExecutionStep.execute(AbstractCaptureStateBeforeExecutionStep.java:43) at org.gradle.internal.execution.steps.AbstractSkipEmptyWorkStep.executeWithNonEmptySources(AbstractSkipEmptyWorkStep.java:125) at org.gradle.internal.execution.steps.AbstractSkipEmptyWorkStep.execute(AbstractSkipEmptyWorkStep.java:56) at org.gradle.internal.execution.steps.AbstractSkipEmptyWorkStep.execute(AbstractSkipEmptyWorkStep.java:36) at org.gradle.internal.execution.steps.legacy.MarkSnapshottingInputsStartedStep.execute(MarkSnapshottingInputsStartedStep.java:38) at org.gradle.internal.execution.steps.LoadPreviousExecutionStateStep.execute(LoadPreviousExecutionStateStep.java:36) at org.gradle.internal.execution.steps.LoadPreviousExecutionStateStep.execute(LoadPreviousExecutionStateStep.java:23) at org.gradle.internal.execution.steps.HandleStaleOutputsStep.execute(HandleStaleOutputsStep.java:75) at org.gradle.internal.execution.steps.HandleStaleOutputsStep.execute(HandleStaleOutputsStep.java:41) at org.gradle.internal.execution.steps.AssignMutableWorkspaceStep.lambda$execute$0(AssignMutableWorkspaceStep.java:35) at org.gradle.api.internal.tasks.execution.TaskExecution$4.withWorkspace(TaskExecution.java:289) at org.gradle.internal.execution.steps.AssignMutableWorkspaceStep.execute(AssignMutableWorkspaceStep.java:31) at org.gradle.internal.execution.steps.AssignMutableWorkspaceStep.execute(AssignMutableWorkspaceStep.java:22) at org.gradle.internal.execution.steps.ChoosePipelineStep.execute(ChoosePipelineStep.java:40) at org.gradle.internal.execution.steps.ChoosePipelineStep.execute(ChoosePipelineStep.java:23) at org.gradle.internal.execution.steps.ExecuteWorkBuildOperationFiringStep.lambda$execute$2(ExecuteWorkBuildOperationFiringStep.java:67) at org.gradle.internal.execution.steps.ExecuteWorkBuildOperationFiringStep.execute(ExecuteWorkBuildOperationFiringStep.java:67) at org.gradle.internal.execution.steps.ExecuteWorkBuildOperationFiringStep.execute(ExecuteWorkBuildOperationFiringStep.java:39) at org.gradle.internal.execution.steps.IdentityCacheStep.execute(IdentityCacheStep.java:46) at org.gradle.internal.execution.steps.IdentityCacheStep.execute(IdentityCacheStep.java:34) at org.gradle.internal.execution.steps.IdentifyStep.execute(IdentifyStep.java:48) at org.gradle.internal.execution.steps.IdentifyStep.execute(IdentifyStep.java:35) at org.gradle.internal.execution.impl.DefaultExecutionEngine$1.execute(DefaultExecutionEngine.java:61) at org.gradle.api.internal.tasks.execution.ExecuteActionsTaskExecuter.executeIfValid(ExecuteActionsTaskExecuter.java:127) at org.gradle.api.internal.tasks.execution.ExecuteActionsTaskExecuter.execute(ExecuteActionsTaskExecuter.java:116) at org.gradle.api.internal.tasks.execution.FinalizePropertiesTaskExecuter.execute(FinalizePropertiesTaskExecuter.java:46) at org.gradle.api.internal.tasks.execution.ResolveTaskExecutionModeExecuter.execute(ResolveTaskExecutionModeExecuter.java:51) at org.gradle.api.internal.tasks.execution.SkipTaskWithNoActionsExecuter.execute(SkipTaskWithNoActionsExecuter.java:57) at org.gradle.api.internal.tasks.execution.SkipOnlyIfTaskExecuter.execute(SkipOnlyIfTaskExecuter.java:74) at org.gradle.api.internal.tasks.execution.CatchExceptionTaskExecuter.execute(CatchExceptionTaskExecuter.java:36) at org.gradle.api.internal.tasks.execution.EventFiringTaskExecuter$1.executeTask(EventFiringTaskExecuter.java:77) at org.gradle.api.internal.tasks.execution.EventFiringTaskExecuter$1.call(EventFiringTaskExecuter.java:55) at org.gradle.api.internal.tasks.execution.EventFiringTaskExecuter$1.call(EventFiringTaskExecuter.java:52) at org.gradle.internal.operations.DefaultBuildOperationRunner$CallableBuildOperationWorker.execute(DefaultBuildOperationRunner.java:200) at org.gradle.internal.operations.DefaultBuildOperationRunner$CallableBuildOperationWorker.execute(DefaultBuildOperationRunner.java:195) at org.gradle.internal.operations.DefaultBuildOperationRunner$2.execute(DefaultBuildOperationRunner.java:66) at org.gradle.internal.operations.DefaultBuildOperationRunner$2.execute(DefaultBuildOperationRunner.java:59) at org.gradle.internal.operations.DefaultBuildOperationRunner.execute(DefaultBuildOperationRunner.java:157) at org.gradle.internal.operations.DefaultBuildOperationRunner.execute(DefaultBuildOperationRunner.java:59) at org.gradle.internal.operations.DefaultBuildOperationRunner.call(DefaultBuildOperationRunner.java:53) at org.gradle.internal.operations.DefaultBuildOperationExecutor.call(DefaultBuildOperationExecutor.java:73) at org.gradle.api.internal.tasks.execution.EventFiringTaskExecuter.execute(EventFiringTaskExecuter.java:52) at org.gradle.execution.plan.LocalTaskNodeExecutor.execute(LocalTaskNodeExecutor.java:42) at org.gradle.execution.taskgraph.DefaultTaskExecutionGraph$InvokeNodeExecutorsAction.execute(DefaultTaskExecutionGraph.java:331) at org.gradle.execution.taskgraph.DefaultTaskExecutionGraph$InvokeNodeExecutorsAction.execute(DefaultTaskExecutionGraph.java:318) at org.gradle.execution.taskgraph.DefaultTaskExecutionGraph$BuildOperationAwareExecutionAction.lambda$execute$0(DefaultTaskExecutionGraph.java:314) at org.gradle.internal.operations.CurrentBuildOperationRef.with(CurrentBuildOperationRef.java:80) at org.gradle.execution.taskgraph.DefaultTaskExecutionGraph$BuildOperationAwareExecutionAction.execute(DefaultTaskExecutionGraph.java:314) at org.gradle.execution.taskgraph.DefaultTaskExecutionGraph$BuildOperationAwareExecutionAction.execute(DefaultTaskExecutionGraph.java:303) at org.gradle.execution.plan.DefaultPlanExecutor$ExecutorWorker.execute(DefaultPlanExecutor.java:463) at org.gradle.execution.plan.DefaultPlanExecutor$ExecutorWorker.run(DefaultPlanExecutor.java:380) at org.gradle.internal.concurrent.ExecutorPolicy$CatchAndRecordFailures.onExecute(ExecutorPolicy.java:64) at org.gradle.internal.concurrent.AbstractManagedExecutor$1.run(AbstractManagedExecutor.java:47) Deprecated Gradle features were used in this build, making it incompatible with Gradle 9.0. You can use '--warning-mode all' to show the individual deprecation warnings and determine if they come from your own scripts or plugins. For more on this, please refer to https://docs.gradle.org/8.7/userguide/command_line_interface.html#sec:command_line_warnings in the Gradle documentation. BUILD FAILED in 419ms 24 actionable tasks: 3 executed, 21 up-to-date
06-17
/** * MIT License * * Copyright (C) 2016-2025 WinToast v1.3.2 - Mohammed Boujemaoui <mohabouje@gmail.com> * * Permission is hereby granted, free of charge, to any person obtaining a copy of * this software and associated documentation files (the "Software"), to deal in * the Software without restriction, including without limitation the rights to * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of * the Software, and to permit persons to whom the Software is furnished to do so, * subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #include "wintoastlib.h" #include <memory> #include <assert.h> #include <unordered_map> #include <array> #include <functional> #pragma comment(lib, "shlwapi") #pragma comment(lib, "user32") #define DEFAULT_SHELL_LINKS_PATH L"\\Microsoft\\Windows\\Start Menu\\Programs\\" #define DEFAULT_LINK_FORMAT L".lnk" #define STATUS_SUCCESS (0x00000000) #ifdef NDEBUG static bool DebugOutputEnabled = false; #else static bool DebugOutputEnabled = true; #endif #define DEBUG_MSG(str) \ do { \ if (DebugOutputEnabled) { \ std::wcout << str << std::endl; \ } \ } while (false) // Quickstart: Handling toast activations from Win32 apps in Windows 10 // https://blogs.msdn.microsoft.com/tiles_and_toasts/2015/10/16/quickstart-handling-toast-activations-from-win32-apps-in-windows-10/ using namespace WinToastLib; void WinToastLib::setDebugOutputEnabled(bool enabled) { DebugOutputEnabled = enabled; } namespace DllImporter { // Function load a function from library template <typename Function> HRESULT loadFunctionFromLibrary(HINSTANCE library, LPCSTR name, Function& func) { if (!library) { return E_INVALIDARG; } func = reinterpret_cast<Function>(GetProcAddress(library, name)); return (func != nullptr) ? S_OK : E_FAIL; } typedef HRESULT(FAR STDAPICALLTYPE* f_SetCurrentProcessExplicitAppUserModelID)(__in PCWSTR AppID); typedef HRESULT(FAR STDAPICALLTYPE* f_PropVariantToString)(_In_ REFPROPVARIANT propvar, _Out_writes_(cch) PWSTR psz, _In_ UINT cch); typedef HRESULT(FAR STDAPICALLTYPE* f_RoGetActivationFactory)(_In_ HSTRING activatableClassId, _In_ REFIID iid, _COM_Outptr_ void** factory); typedef HRESULT(FAR STDAPICALLTYPE* f_WindowsCreateStringReference)(_In_reads_opt_(length + 1) PCWSTR sourceString, UINT32 length, _Out_ HSTRING_HEADER* hstringHeader, _Outptr_result_maybenull_ _Result_nullonfailure_ HSTRING* string); typedef PCWSTR(FAR STDAPICALLTYPE* f_WindowsGetStringRawBuffer)(_In_ HSTRING string, _Out_opt_ UINT32* length); typedef HRESULT(FAR STDAPICALLTYPE* f_WindowsDeleteString)(_In_opt_ HSTRING string); static f_SetCurrentProcessExplicitAppUserModelID SetCurrentProcessExplicitAppUserModelID; static f_PropVariantToString PropVariantToString; static f_RoGetActivationFactory RoGetActivationFactory; static f_WindowsCreateStringReference WindowsCreateStringReference; static f_WindowsGetStringRawBuffer WindowsGetStringRawBuffer; static f_WindowsDeleteString WindowsDeleteString; template <class T> __inline _Check_return_ HRESULT _1_GetActivationFactory(_In_ HSTRING activatableClassId, _COM_Outptr_ T** factory) { return RoGetActivationFactory(activatableClassId, IID_INS_ARGS(factory)); } template <typename T> inline HRESULT Wrap_GetActivationFactory(_In_ HSTRING activatableClassId, _Inout_ Details::ComPtrRef<T> factory) noexcept { return _1_GetActivationFactory(activatableClassId, factory.ReleaseAndGetAddressOf()); } inline HRESULT initialize() { HINSTANCE LibShell32 = LoadLibraryW(L"SHELL32.DLL"); HRESULT hr = loadFunctionFromLibrary(LibShell32, "SetCurrentProcessExplicitAppUserModelID", SetCurrentProcessExplicitAppUserModelID); if (SUCCEEDED(hr)) { HINSTANCE LibPropSys = LoadLibraryW(L"PROPSYS.DLL"); hr = loadFunctionFromLibrary(LibPropSys, "PropVariantToString", PropVariantToString); if (SUCCEEDED(hr)) { HINSTANCE LibComBase = LoadLibraryW(L"COMBASE.DLL"); bool const succeded = SUCCEEDED(loadFunctionFromLibrary(LibComBase, "RoGetActivationFactory", RoGetActivationFactory)) && SUCCEEDED(loadFunctionFromLibrary(LibComBase, "WindowsCreateStringReference", WindowsCreateStringReference)) && SUCCEEDED(loadFunctionFromLibrary(LibComBase, "WindowsGetStringRawBuffer", WindowsGetStringRawBuffer)) && SUCCEEDED(loadFunctionFromLibrary(LibComBase, "WindowsDeleteString", WindowsDeleteString)); return succeded ? S_OK : E_FAIL; } } return hr; } } // namespace DllImporter class WinToastStringWrapper { public: WinToastStringWrapper(_In_reads_(length) PCWSTR stringRef, _In_ UINT32 length) { HRESULT hr = DllImporter::WindowsCreateStringReference(stringRef, length, &_header, &_hstring); if (!SUCCEEDED(hr)) { RaiseException(static_cast<DWORD>(STATUS_INVALID_PARAMETER), 0, 0, nullptr); } } WinToastStringWrapper(_In_ std::wstring const& stringRef) { HRESULT hr = DllImporter::WindowsCreateStringReference(stringRef.c_str(), static_cast<UINT32>(stringRef.length()), &_header, &_hstring); if (FAILED(hr)) { RaiseException(static_cast<DWORD>(STATUS_INVALID_PARAMETER), 0, 0, nullptr); } } ~WinToastStringWrapper() { DllImporter::WindowsDeleteString(_hstring); } inline HSTRING Get() const noexcept { return _hstring; } private: HSTRING _hstring; HSTRING_HEADER _header; }; class InternalDateTime : public IReference<DateTime> { public: static INT64 Now() { FILETIME now; GetSystemTimeAsFileTime(&now); return ((((INT64) now.dwHighDateTime) << 32) | now.dwLowDateTime); } InternalDateTime(DateTime dateTime) : _dateTime(dateTime) {} InternalDateTime(INT64 millisecondsFromNow) { _dateTime.UniversalTime = Now() + millisecondsFromNow * 10000; } virtual ~InternalDateTime() = default; operator INT64() { return _dateTime.UniversalTime; } HRESULT STDMETHODCALLTYPE get_Value(DateTime* dateTime) { *dateTime = _dateTime; return S_OK; } HRESULT STDMETHODCALLTYPE QueryInterface(const IID& riid, void** ppvObject) { if (!ppvObject) { return E_POINTER; } if (riid == __uuidof(IUnknown) || riid == __uuidof(IReference<DateTime>)) { *ppvObject = static_cast<IUnknown*>(static_cast<IReference<DateTime>*>(this)); return S_OK; } return E_NOINTERFACE; } ULONG STDMETHODCALLTYPE Release() { return 1; } ULONG STDMETHODCALLTYPE AddRef() { return 2; } HRESULT STDMETHODCALLTYPE GetIids(ULONG*, IID**) { return E_NOTIMPL; } HRESULT STDMETHODCALLTYPE GetRuntimeClassName(HSTRING*) { return E_NOTIMPL; } HRESULT STDMETHODCALLTYPE GetTrustLevel(TrustLevel*) { return E_NOTIMPL; } protected: DateTime _dateTime; }; namespace Util { typedef LONG NTSTATUS, *PNTSTATUS; typedef NTSTATUS(WINAPI* RtlGetVersionPtr)(PRTL_OSVERSIONINFOW); inline RTL_OSVERSIONINFOW getRealOSVersion() { HMODULE hMod = ::GetModuleHandleW(L"ntdll.dll"); if (hMod) { RtlGetVersionPtr fxPtr = (RtlGetVersionPtr)::GetProcAddress(hMod, "RtlGetVersion"); if (fxPtr != nullptr) { RTL_OSVERSIONINFOW rovi = {0}; rovi.dwOSVersionInfoSize = sizeof(rovi); if (STATUS_SUCCESS == fxPtr(&rovi)) { return rovi; } } } RTL_OSVERSIONINFOW rovi = {0}; return rovi; } inline HRESULT defaultExecutablePath(_In_ WCHAR* path, _In_ DWORD nSize = MAX_PATH) { DWORD written = GetModuleFileNameExW(GetCurrentProcess(), nullptr, path, nSize); DEBUG_MSG("Default executable path: " << path); return (written > 0) ? S_OK : E_FAIL; } inline HRESULT defaultShellLinksDirectory(_In_ WCHAR* path, _In_ DWORD nSize = MAX_PATH) { DWORD written = GetEnvironmentVariableW(L"APPDATA", path, nSize); HRESULT hr = written > 0 ? S_OK : E_INVALIDARG; if (SUCCEEDED(hr)) { errno_t result = wcscat_s(path, nSize, DEFAULT_SHELL_LINKS_PATH); hr = (result == 0) ? S_OK : E_INVALIDARG; DEBUG_MSG("Default shell link path: " << path); } return hr; } inline HRESULT defaultShellLinkPath(_In_ std::wstring const& appname, _In_ WCHAR* path, _In_ DWORD nSize = MAX_PATH) { HRESULT hr = defaultShellLinksDirectory(path, nSize); if (SUCCEEDED(hr)) { std::wstring const appLink(appname + DEFAULT_LINK_FORMAT); errno_t result = wcscat_s(path, nSize, appLink.c_str()); hr = (result == 0) ? S_OK : E_INVALIDARG; DEBUG_MSG("Default shell link file path: " << path); } return hr; } inline std::wstring parentDirectory(WCHAR* path, DWORD size) { size_t lastSeparator = 0; for (size_t i = 0; i < size; i++) { if (path[i] == L'\\' || path[i] == L'/') { lastSeparator = i; } } return {path, lastSeparator}; } inline PCWSTR AsString(_In_ ComPtr<IXmlDocument>& xmlDocument) { HSTRING xml; ComPtr<IXmlNodeSerializer> ser; HRESULT hr = xmlDocument.As<IXmlNodeSerializer>(&ser); hr = ser->GetXml(&xml); if (SUCCEEDED(hr)) { return DllImporter::WindowsGetStringRawBuffer(xml, nullptr); } return nullptr; } inline PCWSTR AsString(_In_ HSTRING hstring) { return DllImporter::WindowsGetStringRawBuffer(hstring, nullptr); } inline HRESULT setNodeStringValue(_In_ std::wstring const& string, _Out_opt_ IXmlNode* node, _Out_ IXmlDocument* xml) { ComPtr<IXmlText> textNode; HRESULT hr = xml->CreateTextNode(WinToastStringWrapper(string).Get(), &textNode); if (SUCCEEDED(hr)) { ComPtr<IXmlNode> stringNode; hr = textNode.As(&stringNode); if (SUCCEEDED(hr)) { ComPtr<IXmlNode> appendedChild; hr = node->AppendChild(stringNode.Get(), &appendedChild); } } return hr; } template <typename FunctorT> inline HRESULT setEventHandlers(_In_ IToastNotification* notification, _In_ std::shared_ptr<IWinToastHandler> eventHandler, _In_ INT64 expirationTime, _Out_ EventRegistrationToken& activatedToken, _Out_ EventRegistrationToken& dismissedToken, _Out_ EventRegistrationToken& failedToken, _In_ FunctorT&& markAsReadyForDeletionFunc) { HRESULT hr = notification->add_Activated( Callback<Implements<RuntimeClassFlags<ClassicCom>, ITypedEventHandler<ToastNotification*, IInspectable*>>>( [eventHandler, markAsReadyForDeletionFunc](IToastNotification* notify, IInspectable* inspectable) { ComPtr<IToastActivatedEventArgs> activatedEventArgs; HRESULT hr = inspectable->QueryInterface(activatedEventArgs.GetAddressOf()); if (SUCCEEDED(hr)) { HSTRING argumentsHandle; hr = activatedEventArgs->get_Arguments(&argumentsHandle); if (SUCCEEDED(hr)) { PCWSTR arguments = Util::AsString(argumentsHandle); if (wcscmp(arguments, L"action=reply") == 0) { ComPtr<IToastActivatedEventArgs2> inputBoxActivatedEventArgs; HRESULT hr2 = inspectable->QueryInterface(inputBoxActivatedEventArgs.GetAddressOf()); if (SUCCEEDED(hr2)) { ComPtr<Collections::IPropertySet> replyHandle; inputBoxActivatedEventArgs->get_UserInput(&replyHandle); ComPtr<__FIMap_2_HSTRING_IInspectable> replyMap; hr = replyHandle.As(&replyMap); if (SUCCEEDED(hr)) { IInspectable* propertySet; hr = replyMap.Get()->Lookup(WinToastStringWrapper(L"textBox").Get(), &propertySet); if (SUCCEEDED(hr)) { ComPtr<IPropertyValue> propertyValue; hr = propertySet->QueryInterface(IID_PPV_ARGS(&propertyValue)); if (SUCCEEDED(hr)) { // Successfully queried IPropertyValue, now extract the value HSTRING userInput; hr = propertyValue->GetString(&userInput); if (SUCCEEDED(hr)) { // Convert the HSTRING to a wide string PCWSTR strValue = Util::AsString(userInput); eventHandler->toastActivated(std::wstring(strValue)); DllImporter::WindowsDeleteString(userInput); return S_OK; } if (userInput != nullptr) { DllImporter::WindowsDeleteString(userInput); } } } } } } if (arguments && *arguments) { eventHandler->toastActivated(static_cast<long>(wcstol(arguments, nullptr, 10))); DllImporter::WindowsDeleteString(argumentsHandle); markAsReadyForDeletionFunc(); return S_OK; } DllImporter::WindowsDeleteString(argumentsHandle); } } eventHandler->toastActivated(); markAsReadyForDeletionFunc(); return S_OK; }) .Get(), &activatedToken); if (SUCCEEDED(hr)) { hr = notification->add_Dismissed( Callback<Implements<RuntimeClassFlags<ClassicCom>, ITypedEventHandler<ToastNotification*, ToastDismissedEventArgs*>>>( [eventHandler, expirationTime, markAsReadyForDeletionFunc](IToastNotification* notify, IToastDismissedEventArgs* e) { ToastDismissalReason reason; if (SUCCEEDED(e->get_Reason(&reason))) { if (reason == ToastDismissalReason_UserCanceled && expirationTime && InternalDateTime::Now() >= expirationTime) { reason = ToastDismissalReason_TimedOut; } eventHandler->toastDismissed(static_cast<IWinToastHandler::WinToastDismissalReason>(reason)); } markAsReadyForDeletionFunc(); return S_OK; }) .Get(), &dismissedToken); if (SUCCEEDED(hr)) { hr = notification->add_Failed( Callback<Implements<RuntimeClassFlags<ClassicCom>, ITypedEventHandler<ToastNotification*, ToastFailedEventArgs*>>>( [eventHandler, markAsReadyForDeletionFunc](IToastNotification* notify, IToastFailedEventArgs* e) { eventHandler->toastFailed(); markAsReadyForDeletionFunc(); return S_OK; }) .Get(), &failedToken); } } return hr; } inline HRESULT addAttribute(_In_ IXmlDocument* xml, std::wstring const& name, IXmlNamedNodeMap* attributeMap) { ComPtr<ABI::Windows::Data::Xml::Dom::IXmlAttribute> srcAttribute; HRESULT hr = xml->CreateAttribute(WinToastStringWrapper(name).Get(), &srcAttribute); if (SUCCEEDED(hr)) { ComPtr<IXmlNode> node; hr = srcAttribute.As(&node); if (SUCCEEDED(hr)) { ComPtr<IXmlNode> pNode; hr = attributeMap->SetNamedItem(node.Get(), &pNode); } } return hr; } inline HRESULT createElement(_In_ IXmlDocument* xml, _In_ std::wstring const& root_node, _In_ std::wstring const& element_name, _In_ std::vector<std::wstring> const& attribute_names) { ComPtr<IXmlNodeList> rootList; HRESULT hr = xml->GetElementsByTagName(WinToastStringWrapper(root_node).Get(), &rootList); if (SUCCEEDED(hr)) { ComPtr<IXmlNode> root; hr = rootList->Item(0, &root); if (SUCCEEDED(hr)) { ComPtr<ABI::Windows::Data::Xml::Dom::IXmlElement> audioElement; hr = xml->CreateElement(WinToastStringWrapper(element_name).Get(), &audioElement); if (SUCCEEDED(hr)) { ComPtr<IXmlNode> audioNodeTmp; hr = audioElement.As(&audioNodeTmp); if (SUCCEEDED(hr)) { ComPtr<IXmlNode> audioNode; hr = root->AppendChild(audioNodeTmp.Get(), &audioNode); if (SUCCEEDED(hr)) { ComPtr<IXmlNamedNodeMap> attributes; hr = audioNode->get_Attributes(&attributes); if (SUCCEEDED(hr)) { for (auto const& it : attribute_names) { hr = addAttribute(xml, it, attributes.Get()); } } } } } } } return hr; } } // namespace Util WinToast* WinToast::instance() { thread_local static WinToast instance; return &instance; } WinToast::WinToast() : _isInitialized(false), _hasCoInitialized(false) { if (!isCompatible()) { DEBUG_MSG(L"Warning: Your system is not compatible with this library "); } } WinToast::~WinToast() { clear(); if (_hasCoInitialized) { CoUninitialize(); } } void WinToast::setAppName(_In_ std::wstring const& appName) { _appName = appName; } void WinToast::setAppUserModelId(_In_ std::wstring const& aumi) { _aumi = aumi; DEBUG_MSG(L"Default App User Model Id: " << _aumi.c_str()); } void WinToast::setShortcutPolicy(_In_ ShortcutPolicy shortcutPolicy) { _shortcutPolicy = shortcutPolicy; } bool WinToast::isCompatible() { DllImporter::initialize(); return !((DllImporter::SetCurrentProcessExplicitAppUserModelID == nullptr) || (DllImporter::PropVariantToString == nullptr) || (DllImporter::RoGetActivationFactory == nullptr) || (DllImporter::WindowsCreateStringReference == nullptr) || (DllImporter::WindowsDeleteString == nullptr)); } bool WinToastLib::WinToast::isSupportingModernFeatures() { constexpr auto MinimumSupportedVersion = 6; return Util::getRealOSVersion().dwMajorVersion > MinimumSupportedVersion; } bool WinToastLib::WinToast::isWin10AnniversaryOrHigher() { return Util::getRealOSVersion().dwBuildNumber >= 14393; } std::wstring WinToast::configureAUMI(_In_ std::wstring const& companyName, _In_ std::wstring const& productName, _In_ std::wstring const& subProduct, _In_ std::wstring const& versionInformation) { std::wstring aumi = companyName; aumi += L"." + productName; if (subProduct.length() > 0) { aumi += L"." + subProduct; if (versionInformation.length() > 0) { aumi += L"." + versionInformation; } } if (aumi.length() > SCHAR_MAX) { DEBUG_MSG("Error: max size allowed for AUMI: 128 characters."); } return aumi; } std::wstring const& WinToast::strerror(WinToastError error) { static std::unordered_map<WinToastError, std::wstring> const Labels = { {WinToastError::NoError, L"No error. The process was executed correctly" }, {WinToastError::NotInitialized, L"The library has not been initialized" }, {WinToastError::SystemNotSupported, L"The OS does not support WinToast" }, {WinToastError::ShellLinkNotCreated, L"The library was not able to create a Shell Link for the app" }, {WinToastError::InvalidAppUserModelID, L"The AUMI is not a valid one" }, {WinToastError::InvalidParameters, L"Invalid parameters, please double-check the AUMI or App Name" }, {WinToastError::NotDisplayed, L"The toast was created correctly but WinToast was not able to display the toast"}, {WinToastError::UnknownError, L"Unknown error" } }; auto const iter = Labels.find(error); assert(iter != Labels.end()); return iter->second; } enum WinToast::ShortcutResult WinToast::createShortcut() { if (_aumi.empty() || _appName.empty()) { DEBUG_MSG(L"Error: App User Model Id or Appname is empty!"); return SHORTCUT_MISSING_PARAMETERS; } if (!isCompatible()) { DEBUG_MSG(L"Your OS is not compatible with this library! =("); return SHORTCUT_INCOMPATIBLE_OS; } if (!_hasCoInitialized) { HRESULT initHr = CoInitializeEx(nullptr, COINIT::COINIT_MULTITHREADED); if (initHr != RPC_E_CHANGED_MODE) { if (FAILED(initHr) && initHr != S_FALSE) { DEBUG_MSG(L"Error on COM library initialization!"); return SHORTCUT_COM_INIT_FAILURE; } else { _hasCoInitialized = true; } } } bool wasChanged; HRESULT hr = validateShellLinkHelper(wasChanged); if (SUCCEEDED(hr)) { return wasChanged ? SHORTCUT_WAS_CHANGED : SHORTCUT_UNCHANGED; } hr = createShellLinkHelper(); return SUCCEEDED(hr) ? SHORTCUT_WAS_CREATED : SHORTCUT_CREATE_FAILED; } bool WinToast::initialize(_Out_opt_ WinToastError* error) { _isInitialized = false; setError(error, WinToastError::NoError); if (!isCompatible()) { setError(error, WinToastError::SystemNotSupported); DEBUG_MSG(L"Error: system not supported."); return false; } if (_aumi.empty() || _appName.empty()) { setError(error, WinToastError::InvalidParameters); DEBUG_MSG(L"Error while initializing, did you set up a valid AUMI and App name?"); return false; } if (_shortcutPolicy != SHORTCUT_POLICY_IGNORE) { if (createShortcut() < 0) { setError(error, WinToastError::ShellLinkNotCreated); DEBUG_MSG(L"Error while attaching the AUMI to the current proccess =("); return false; } } if (FAILED(DllImporter::SetCurrentProcessExplicitAppUserModelID(_aumi.c_str()))) { setError(error, WinToastError::InvalidAppUserModelID); DEBUG_MSG(L"Error while attaching the AUMI to the current proccess =("); return false; } _isInitialized = true; return _isInitialized; } bool WinToast::isInitialized() const { return _isInitialized; } std::wstring const& WinToast::appName() const { return _appName; } std::wstring const& WinToast::appUserModelId() const { return _aumi; } HRESULT WinToast::validateShellLinkHelper(_Out_ bool& wasChanged) { WCHAR path[MAX_PATH] = {L'\0'}; Util::defaultShellLinkPath(_appName, path); // Check if the file exist DWORD attr = GetFileAttributesW(path); if (attr >= 0xFFFFFFF) { DEBUG_MSG("Error, shell link not found. Try to create a new one in: " << path); return E_FAIL; } // Let's load the file as shell link to validate. // - Create a shell link // - Create a persistant file // - Load the path as data for the persistant file // - Read the property AUMI and validate with the current // - Review if AUMI is equal. ComPtr<IShellLink> shellLink; HRESULT hr = CoCreateInstance(CLSID_ShellLink, nullptr, CLSCTX_INPROC_SERVER, IID_PPV_ARGS(&shellLink)); if (SUCCEEDED(hr)) { ComPtr<IPersistFile> persistFile; hr = shellLink.As(&persistFile); if (SUCCEEDED(hr)) { hr = persistFile->Load(path, STGM_READWRITE); if (SUCCEEDED(hr)) { ComPtr<IPropertyStore> propertyStore; hr = shellLink.As(&propertyStore); if (SUCCEEDED(hr)) { PROPVARIANT appIdPropVar; hr = propertyStore->GetValue(PKEY_AppUserModel_ID, &appIdPropVar); if (SUCCEEDED(hr)) { WCHAR AUMI[MAX_PATH]; hr = DllImporter::PropVariantToString(appIdPropVar, AUMI, MAX_PATH); wasChanged = false; if (FAILED(hr) || _aumi != AUMI) { if (_shortcutPolicy == SHORTCUT_POLICY_REQUIRE_CREATE) { // AUMI Changed for the same app, let's update the current value! =) wasChanged = true; PropVariantClear(&appIdPropVar); hr = InitPropVariantFromString(_aumi.c_str(), &appIdPropVar); if (SUCCEEDED(hr)) { hr = propertyStore->SetValue(PKEY_AppUserModel_ID, appIdPropVar); if (SUCCEEDED(hr)) { hr = propertyStore->Commit(); if (SUCCEEDED(hr) && SUCCEEDED(persistFile->IsDirty())) { hr = persistFile->Save(path, TRUE); } } } } else { // Not allowed to touch the shortcut to fix the AUMI hr = E_FAIL; } } PropVariantClear(&appIdPropVar); } } } } } return hr; } HRESULT WinToast::createShellLinkHelper() { if (_shortcutPolicy != SHORTCUT_POLICY_REQUIRE_CREATE) { return E_FAIL; } WCHAR exePath[MAX_PATH]{L'\0'}; WCHAR slPath[MAX_PATH]{L'\0'}; Util::defaultShellLinkPath(_appName, slPath); Util::defaultExecutablePath(exePath); std::wstring exeDir = Util::parentDirectory(exePath, sizeof(exePath) / sizeof(exePath[0])); ComPtr<IShellLinkW> shellLink; HRESULT hr = CoCreateInstance(CLSID_ShellLink, nullptr, CLSCTX_INPROC_SERVER, IID_PPV_ARGS(&shellLink)); if (SUCCEEDED(hr)) { hr = shellLink->SetPath(exePath); if (SUCCEEDED(hr)) { hr = shellLink->SetArguments(L""); if (SUCCEEDED(hr)) { hr = shellLink->SetWorkingDirectory(exeDir.c_str()); if (SUCCEEDED(hr)) { ComPtr<IPropertyStore> propertyStore; hr = shellLink.As(&propertyStore); if (SUCCEEDED(hr)) { PROPVARIANT appIdPropVar; hr = InitPropVariantFromString(_aumi.c_str(), &appIdPropVar); if (SUCCEEDED(hr)) { hr = propertyStore->SetValue(PKEY_AppUserModel_ID, appIdPropVar); if (SUCCEEDED(hr)) { hr = propertyStore->Commit(); if (SUCCEEDED(hr)) { ComPtr<IPersistFile> persistFile; hr = shellLink.As(&persistFile); if (SUCCEEDED(hr)) { hr = persistFile->Save(slPath, TRUE); } } } PropVariantClear(&appIdPropVar); } } } } } } return hr; } INT64 WinToast::showToast(_In_ WinToastTemplate const& toast, _In_ IWinToastHandler* eventHandler, _Out_ WinToastError* error) { std::shared_ptr<IWinToastHandler> handler(eventHandler); setError(error, WinToastError::NoError); INT64 id = -1; if (!isInitialized()) { setError(error, WinToastError::NotInitialized); DEBUG_MSG("Error when launching the toast. WinToast is not initialized."); return id; } if (!handler) { setError(error, WinToastError::InvalidHandler); DEBUG_MSG("Error when launching the toast. Handler cannot be nullptr."); return id; } ComPtr<IToastNotificationManagerStatics> notificationManager; HRESULT hr = DllImporter::Wrap_GetActivationFactory( WinToastStringWrapper(RuntimeClass_Windows_UI_Notifications_ToastNotificationManager).Get(), &notificationManager); if (SUCCEEDED(hr)) { ComPtr<IToastNotifier> notifier; hr = notificationManager->CreateToastNotifierWithId(WinToastStringWrapper(_aumi).Get(), &notifier); if (SUCCEEDED(hr)) { ComPtr<IToastNotificationFactory> notificationFactory; hr = DllImporter::Wrap_GetActivationFactory( WinToastStringWrapper(RuntimeClass_Windows_UI_Notifications_ToastNotification).Get(), &notificationFactory); if (SUCCEEDED(hr)) { ComPtr<IXmlDocument> xmlDocument; hr = notificationManager->GetTemplateContent(ToastTemplateType(toast.type()), &xmlDocument); if (SUCCEEDED(hr) && toast.isToastGeneric()) { hr = setBindToastGenericHelper(xmlDocument.Get()); } if (SUCCEEDED(hr)) { for (UINT32 i = 0, fieldsCount = static_cast<UINT32>(toast.textFieldsCount()); i < fieldsCount && SUCCEEDED(hr); i++) { hr = setTextFieldHelper(xmlDocument.Get(), toast.textField(WinToastTemplate::TextField(i)), i); } // Modern feature are supported Windows > Windows 10 if (SUCCEEDED(hr) && isSupportingModernFeatures()) { // Note that we do this *after* using toast.textFieldsCount() to // iterate/fill the template's text fields, since we're adding yet another text field. if (SUCCEEDED(hr) && !toast.attributionText().empty()) { hr = setAttributionTextFieldHelper(xmlDocument.Get(), toast.attributionText()); } std::array<WCHAR, 12> buf; for (std::size_t i = 0, actionsCount = toast.actionsCount(); i < actionsCount && SUCCEEDED(hr); i++) { _snwprintf_s(buf.data(), buf.size(), _TRUNCATE, L"%zd", i); hr = addActionHelper(xmlDocument.Get(), toast.actionLabel(i), buf.data()); } if (SUCCEEDED(hr)) { hr = (toast.audioPath().empty() && toast.audioOption() == WinToastTemplate::AudioOption::Default) ? hr : setAudioFieldHelper(xmlDocument.Get(), toast.audioPath(), toast.audioOption()); } if (SUCCEEDED(hr) && toast.duration() != WinToastTemplate::Duration::System) { hr = addDurationHelper(xmlDocument.Get(), (toast.duration() == WinToastTemplate::Duration::Short) ? L"short" : L"long"); } if (SUCCEEDED(hr) && toast.isInput()) { hr = addInputHelper(xmlDocument.Get()); } if (SUCCEEDED(hr)) { hr = addScenarioHelper(xmlDocument.Get(), toast.scenario()); } } else { DEBUG_MSG("Modern features (Actions/Sounds/Attributes) not supported in this os version"); } if (SUCCEEDED(hr)) { bool isWin10AnniversaryOrAbove = WinToast::isWin10AnniversaryOrHigher(); bool isCircleCropHint = isWin10AnniversaryOrAbove ? toast.isCropHintCircle() : false; hr = toast.hasImage() ? setImageFieldHelper(xmlDocument.Get(), toast.imagePath(), toast.isToastGeneric(), isCircleCropHint) : hr; if (SUCCEEDED(hr) && isWin10AnniversaryOrAbove && toast.hasHeroImage()) { hr = setHeroImageHelper(xmlDocument.Get(), toast.heroImagePath(), toast.isInlineHeroImage()); } if (SUCCEEDED(hr)) { ComPtr<IToastNotification> notification; hr = notificationFactory->CreateToastNotification(xmlDocument.Get(), &notification); if (SUCCEEDED(hr)) { INT64 expiration = 0, relativeExpiration = toast.expiration(); if (relativeExpiration > 0) { InternalDateTime expirationDateTime(relativeExpiration); expiration = expirationDateTime; hr = notification->put_ExpirationTime(&expirationDateTime); } EventRegistrationToken activatedToken, dismissedToken, failedToken; GUID guid; HRESULT hrGuid = CoCreateGuid(&guid); id = guid.Data1; if (SUCCEEDED(hr) && SUCCEEDED(hrGuid)) { hr = Util::setEventHandlers(notification.Get(), handler, expiration, activatedToken, dismissedToken, failedToken, [this, id]() { markAsReadyForDeletion(id); }); if (FAILED(hr)) { setError(error, WinToastError::InvalidHandler); } } if (SUCCEEDED(hr)) { if (SUCCEEDED(hr)) { std::lock_guard<std::mutex> lock(m_mutex); _buffer.emplace(id, NotifyData(notification, activatedToken, dismissedToken, failedToken)); DEBUG_MSG("xml: " << Util::AsString(xmlDocument)); hr = notifier->Show(notification.Get()); if (FAILED(hr)) { setError(error, WinToastError::NotDisplayed); } } } } } } } } } } return FAILED(hr) ? -1 : id; } ComPtr<IToastNotifier> WinToast::notifier(_In_ bool* succeded) const { ComPtr<IToastNotificationManagerStatics> notificationManager; ComPtr<IToastNotifier> notifier; HRESULT hr = DllImporter::Wrap_GetActivationFactory( WinToastStringWrapper(RuntimeClass_Windows_UI_Notifications_ToastNotificationManager).Get(), &notificationManager); if (SUCCEEDED(hr)) { hr = notificationManager->CreateToastNotifierWithId(WinToastStringWrapper(_aumi).Get(), &notifier); } *succeded = SUCCEEDED(hr); return notifier; } void WinToast::markAsReadyForDeletion(_In_ INT64 id) { std::lock_guard<std::mutex> lock(m_mutex); // Flush the buffer by removing all the toasts that are ready for deletion for (auto it = _buffer.begin(); it != _buffer.end();) { if (it->second.isReadyForDeletion()) { it->second.RemoveTokens(); it = _buffer.erase(it); } else { ++it; } } // Mark the toast as ready for deletion (if it exists) so that it will be removed from the buffer in the next iteration auto const iter = _buffer.find(id); if (iter != _buffer.end()) { _buffer[id].markAsReadyForDeletion(); } } bool WinToast::hideToast(_In_ INT64 id) { std::lock_guard<std::mutex> lock(m_mutex); if (!isInitialized()) { DEBUG_MSG("Error when hiding the toast. WinToast is not initialized."); return false; } auto iter = _buffer.find(id); if (iter == _buffer.end()) { return false; } auto succeded = false; auto notify = notifier(&succeded); if (!succeded) { return false; } auto& notifyData = iter->second; auto result = notify->Hide(notifyData.notification()); if (FAILED(result)) { DEBUG_MSG("Error when hiding the toast. Error code: " << result); return false; } notifyData.RemoveTokens(); _buffer.erase(iter); return SUCCEEDED(result); } void WinToast::clear() { auto succeded = false; auto notify = notifier(&succeded); if (!succeded) { return; } std::lock_guard<std::mutex> lock(m_mutex); auto safeCopy = _buffer; for (auto& data : safeCopy) { auto& notifyData = data.second; notify->Hide(notifyData.notification()); notifyData.RemoveTokens(); } _buffer.clear(); } // // Available as of Windows 10 Anniversary Update // Ref: https://docs.microsoft.com/en-us/windows/uwp/design/shell/tiles-and-notifications/adaptive-interactive-toasts // // NOTE: This will add a new text field, so be aware when iterating over // the toast's text fields or getting a count of them. // HRESULT WinToast::setAttributionTextFieldHelper(_In_ IXmlDocument* xml, _In_ std::wstring const& text) { Util::createElement(xml, L"binding", L"text", {L"placement"}); ComPtr<IXmlNodeList> nodeList; HRESULT hr = xml->GetElementsByTagName(WinToastStringWrapper(L"text").Get(), &nodeList); if (SUCCEEDED(hr)) { UINT32 nodeListLength; hr = nodeList->get_Length(&nodeListLength); if (SUCCEEDED(hr)) { for (UINT32 i = 0; i < nodeListLength; i++) { ComPtr<IXmlNode> textNode; hr = nodeList->Item(i, &textNode); if (SUCCEEDED(hr)) { ComPtr<IXmlNamedNodeMap> attributes; hr = textNode->get_Attributes(&attributes); if (SUCCEEDED(hr)) { ComPtr<IXmlNode> editedNode; if (SUCCEEDED(hr)) { hr = attributes->GetNamedItem(WinToastStringWrapper(L"placement").Get(), &editedNode); if (FAILED(hr) || !editedNode) { continue; } hr = Util::setNodeStringValue(L"attribution", editedNode.Get(), xml); if (SUCCEEDED(hr)) { return setTextFieldHelper(xml, text, i); } } } } } } } return hr; } HRESULT WinToast::addDurationHelper(_In_ IXmlDocument* xml, _In_ std::wstring const& duration) { ComPtr<IXmlNodeList> nodeList; HRESULT hr = xml->GetElementsByTagName(WinToastStringWrapper(L"toast").Get(), &nodeList); if (SUCCEEDED(hr)) { UINT32 length; hr = nodeList->get_Length(&length); if (SUCCEEDED(hr)) { ComPtr<IXmlNode> toastNode; hr = nodeList->Item(0, &toastNode); if (SUCCEEDED(hr)) { ComPtr<IXmlElement> toastElement; hr = toastNode.As(&toastElement); if (SUCCEEDED(hr)) { hr = toastElement->SetAttribute(WinToastStringWrapper(L"duration").Get(), WinToastStringWrapper(duration).Get()); } } } } return hr; } HRESULT WinToast::addScenarioHelper(_In_ IXmlDocument* xml, _In_ std::wstring const& scenario) { ComPtr<IXmlNodeList> nodeList; HRESULT hr = xml->GetElementsByTagName(WinToastStringWrapper(L"toast").Get(), &nodeList); if (SUCCEEDED(hr)) { UINT32 length; hr = nodeList->get_Length(&length); if (SUCCEEDED(hr)) { ComPtr<IXmlNode> toastNode; hr = nodeList->Item(0, &toastNode); if (SUCCEEDED(hr)) { ComPtr<IXmlElement> toastElement; hr = toastNode.As(&toastElement); if (SUCCEEDED(hr)) { hr = toastElement->SetAttribute(WinToastStringWrapper(L"scenario").Get(), WinToastStringWrapper(scenario).Get()); } } } } return hr; } HRESULT WinToast::addInputHelper(_In_ IXmlDocument* xml) { std::vector<std::wstring> attrbs; attrbs.push_back(L"id"); attrbs.push_back(L"type"); attrbs.push_back(L"placeHolderContent"); std::vector<std::wstring> attrbs2; attrbs2.push_back(L"content"); attrbs2.push_back(L"arguments"); Util::createElement(xml, L"toast", L"actions", {}); Util::createElement(xml, L"actions", L"input", attrbs); Util::createElement(xml, L"actions", L"action", attrbs2); ComPtr<IXmlNodeList> nodeList; HRESULT hr = xml->GetElementsByTagName(WinToastStringWrapper(L"input").Get(), &nodeList); if (SUCCEEDED(hr)) { ComPtr<IXmlNode> inputNode; hr = nodeList->Item(0, &inputNode); if (SUCCEEDED(hr)) { ComPtr<IXmlElement> toastElement; hr = inputNode.As(&toastElement); if (SUCCEEDED(hr)) { toastElement->SetAttribute(WinToastStringWrapper(L"id").Get(), WinToastStringWrapper(L"textBox").Get()); toastElement->SetAttribute(WinToastStringWrapper(L"type").Get(), WinToastStringWrapper(L"text").Get()); hr = toastElement->SetAttribute(WinToastStringWrapper(L"placeHolderContent").Get(), WinToastStringWrapper(L"...").Get()); } } } ComPtr<IXmlNodeList> nodeList2; hr = xml->GetElementsByTagName(WinToastStringWrapper(L"action").Get(), &nodeList2); if (SUCCEEDED(hr)) { ComPtr<IXmlNode> actionNode; hr = nodeList2->Item(0, &actionNode); if (SUCCEEDED(hr)) { ComPtr<IXmlElement> actionElement; hr = actionNode.As(&actionElement); if (SUCCEEDED(hr)) { actionElement->SetAttribute(WinToastStringWrapper(L"content").Get(), WinToastStringWrapper(L"Reply").Get()); actionElement->SetAttribute(WinToastStringWrapper(L"arguments").Get(), WinToastStringWrapper(L"action=reply").Get()); actionElement->SetAttribute(WinToastStringWrapper(L"hint-inputId").Get(), WinToastStringWrapper(L"textBox").Get()); } } } return hr; } HRESULT WinToast::setTextFieldHelper(_In_ IXmlDocument* xml, _In_ std::wstring const& text, _In_ UINT32 pos) { ComPtr<IXmlNodeList> nodeList; HRESULT hr = xml->GetElementsByTagName(WinToastStringWrapper(L"text").Get(), &nodeList); if (SUCCEEDED(hr)) { ComPtr<IXmlNode> node; hr = nodeList->Item(pos, &node); if (SUCCEEDED(hr)) { hr = Util::setNodeStringValue(text, node.Get(), xml); } } return hr; } HRESULT WinToast::setBindToastGenericHelper(_In_ IXmlDocument* xml) { ComPtr<IXmlNodeList> nodeList; HRESULT hr = xml->GetElementsByTagName(WinToastStringWrapper(L"binding").Get(), &nodeList); if (SUCCEEDED(hr)) { UINT32 length; hr = nodeList->get_Length(&length); if (SUCCEEDED(hr)) { ComPtr<IXmlNode> toastNode; hr = nodeList->Item(0, &toastNode); if (SUCCEEDED(hr)) { ComPtr<IXmlElement> toastElement; hr = toastNode.As(&toastElement); if (SUCCEEDED(hr)) { hr = toastElement->SetAttribute(WinToastStringWrapper(L"template").Get(), WinToastStringWrapper(L"ToastGeneric").Get()); } } } } return hr; } HRESULT WinToast::setImageFieldHelper(_In_ IXmlDocument* xml, _In_ std::wstring const& path, _In_ bool isToastGeneric, _In_ bool isCropHintCircle) { assert(path.size() < MAX_PATH); wchar_t imagePath[MAX_PATH] = L"file:///"; HRESULT hr = StringCchCatW(imagePath, MAX_PATH, path.c_str()); if (SUCCEEDED(hr)) { ComPtr<IXmlNodeList> nodeList; HRESULT hr = xml->GetElementsByTagName(WinToastStringWrapper(L"image").Get(), &nodeList); if (SUCCEEDED(hr)) { ComPtr<IXmlNode> node; hr = nodeList->Item(0, &node); ComPtr<IXmlElement> imageElement; HRESULT hrImage = node.As(&imageElement); if (SUCCEEDED(hr) && SUCCEEDED(hrImage) && isToastGeneric) { hr = imageElement->SetAttribute(WinToastStringWrapper(L"placement").Get(), WinToastStringWrapper(L"appLogoOverride").Get()); if (SUCCEEDED(hr) && isCropHintCircle) { hr = imageElement->SetAttribute(WinToastStringWrapper(L"hint-crop").Get(), WinToastStringWrapper(L"circle").Get()); } } if (SUCCEEDED(hr)) { ComPtr<IXmlNamedNodeMap> attributes; hr = node->get_Attributes(&attributes); if (SUCCEEDED(hr)) { ComPtr<IXmlNode> editedNode; hr = attributes->GetNamedItem(WinToastStringWrapper(L"src").Get(), &editedNode); if (SUCCEEDED(hr)) { Util::setNodeStringValue(imagePath, editedNode.Get(), xml); } } } } } return hr; } HRESULT WinToast::setAudioFieldHelper(_In_ IXmlDocument* xml, _In_ std::wstring const& path, _In_opt_ WinToastTemplate::AudioOption option) { std::vector<std::wstring> attrs; if (!path.empty()) { attrs.push_back(L"src"); } if (option == WinToastTemplate::AudioOption::Loop) { attrs.push_back(L"loop"); } if (option == WinToastTemplate::AudioOption::Silent) { attrs.push_back(L"silent"); } Util::createElement(xml, L"toast", L"audio", attrs); ComPtr<IXmlNodeList> nodeList; HRESULT hr = xml->GetElementsByTagName(WinToastStringWrapper(L"audio").Get(), &nodeList); if (SUCCEEDED(hr)) { ComPtr<IXmlNode> node; hr = nodeList->Item(0, &node); if (SUCCEEDED(hr)) { ComPtr<IXmlNamedNodeMap> attributes; hr = node->get_Attributes(&attributes); if (SUCCEEDED(hr)) { ComPtr<IXmlNode> editedNode; if (!path.empty()) { if (SUCCEEDED(hr)) { hr = attributes->GetNamedItem(WinToastStringWrapper(L"src").Get(), &editedNode); if (SUCCEEDED(hr)) { hr = Util::setNodeStringValue(path, editedNode.Get(), xml); } } } if (SUCCEEDED(hr)) { switch (option) { case WinToastTemplate::AudioOption::Loop: hr = attributes->GetNamedItem(WinToastStringWrapper(L"loop").Get(), &editedNode); if (SUCCEEDED(hr)) { hr = Util::setNodeStringValue(L"true", editedNode.Get(), xml); } break; case WinToastTemplate::AudioOption::Silent: hr = attributes->GetNamedItem(WinToastStringWrapper(L"silent").Get(), &editedNode); if (SUCCEEDED(hr)) { hr = Util::setNodeStringValue(L"true", editedNode.Get(), xml); } default: break; } } } } } return hr; } HRESULT WinToast::addActionHelper(_In_ IXmlDocument* xml, _In_ std::wstring const& content, _In_ std::wstring const& arguments) { ComPtr<IXmlNodeList> nodeList; HRESULT hr = xml->GetElementsByTagName(WinToastStringWrapper(L"actions").Get(), &nodeList); if (SUCCEEDED(hr)) { UINT32 length; hr = nodeList->get_Length(&length); if (SUCCEEDED(hr)) { ComPtr<IXmlNode> actionsNode; if (length > 0) { hr = nodeList->Item(0, &actionsNode); } else { hr = xml->GetElementsByTagName(WinToastStringWrapper(L"toast").Get(), &nodeList); if (SUCCEEDED(hr)) { hr = nodeList->get_Length(&length); if (SUCCEEDED(hr)) { ComPtr<IXmlNode> toastNode; hr = nodeList->Item(0, &toastNode); if (SUCCEEDED(hr)) { ComPtr<IXmlElement> toastElement; hr = toastNode.As(&toastElement); if (SUCCEEDED(hr)) { hr = toastElement->SetAttribute(WinToastStringWrapper(L"template").Get(), WinToastStringWrapper(L"ToastGeneric").Get()); } if (SUCCEEDED(hr)) { hr = toastElement->SetAttribute(WinToastStringWrapper(L"duration").Get(), WinToastStringWrapper(L"long").Get()); } if (SUCCEEDED(hr)) { ComPtr<IXmlElement> actionsElement; hr = xml->CreateElement(WinToastStringWrapper(L"actions").Get(), &actionsElement); if (SUCCEEDED(hr)) { hr = actionsElement.As(&actionsNode); if (SUCCEEDED(hr)) { ComPtr<IXmlNode> appendedChild; hr = toastNode->AppendChild(actionsNode.Get(), &appendedChild); } } } } } } } if (SUCCEEDED(hr)) { ComPtr<IXmlElement> actionElement; hr = xml->CreateElement(WinToastStringWrapper(L"action").Get(), &actionElement); if (SUCCEEDED(hr)) { hr = actionElement->SetAttribute(WinToastStringWrapper(L"content").Get(), WinToastStringWrapper(content).Get()); } if (SUCCEEDED(hr)) { hr = actionElement->SetAttribute(WinToastStringWrapper(L"arguments").Get(), WinToastStringWrapper(arguments).Get()); } if (SUCCEEDED(hr)) { ComPtr<IXmlNode> actionNode; hr = actionElement.As(&actionNode); if (SUCCEEDED(hr)) { ComPtr<IXmlNode> appendedChild; hr = actionsNode->AppendChild(actionNode.Get(), &appendedChild); } } } } } return hr; } HRESULT WinToast::setHeroImageHelper(_In_ IXmlDocument* xml, _In_ std::wstring const& path, _In_ bool isInlineImage) { ComPtr<IXmlNodeList> nodeList; HRESULT hr = xml->GetElementsByTagName(WinToastStringWrapper(L"binding").Get(), &nodeList); if (SUCCEEDED(hr)) { UINT32 length; hr = nodeList->get_Length(&length); if (SUCCEEDED(hr)) { ComPtr<IXmlNode> bindingNode; if (length > 0) { hr = nodeList->Item(0, &bindingNode); } if (SUCCEEDED(hr)) { ComPtr<IXmlElement> imageElement; hr = xml->CreateElement(WinToastStringWrapper(L"image").Get(), &imageElement); if (SUCCEEDED(hr) && isInlineImage == false) { hr = imageElement->SetAttribute(WinToastStringWrapper(L"placement").Get(), WinToastStringWrapper(L"hero").Get()); } if (SUCCEEDED(hr)) { hr = imageElement->SetAttribute(WinToastStringWrapper(L"src").Get(), WinToastStringWrapper(path).Get()); } if (SUCCEEDED(hr)) { ComPtr<IXmlNode> actionNode; hr = imageElement.As(&actionNode); if (SUCCEEDED(hr)) { ComPtr<IXmlNode> appendedChild; hr = bindingNode->AppendChild(actionNode.Get(), &appendedChild); } } } } } return hr; } void WinToast::setError(_Out_opt_ WinToastError* error, _In_ WinToastError value) { if (error) { *error = value; } } WinToastTemplate::WinToastTemplate(_In_ WinToastTemplateType type) : _type(type) { constexpr static std::size_t TextFieldsCount[] = {1, 2, 2, 3, 1, 2, 2, 3}; _textFields = std::vector<std::wstring>(TextFieldsCount[type], L""); } WinToastTemplate::~WinToastTemplate() { _textFields.clear(); } void WinToastTemplate::setTextField(_In_ std::wstring const& txt, _In_ WinToastTemplate::TextField pos) { auto const position = static_cast<std::size_t>(pos); if (position >= _textFields.size()) { DEBUG_MSG("The selected template type supports only " << _textFields.size() << " text lines"); return; } _textFields[position] = txt; } void WinToastTemplate::setImagePath(_In_ std::wstring const& imgPath, _In_ CropHint cropHint) { _imagePath = imgPath; _cropHint = cropHint; } void WinToastTemplate::setHeroImagePath(_In_ std::wstring const& imgPath, _In_ bool inlineImage) { _heroImagePath = imgPath; _inlineHeroImage = inlineImage; } void WinToastTemplate::setAudioPath(_In_ std::wstring const& audioPath) { _audioPath = audioPath; } void WinToastTemplate::setAudioPath(_In_ AudioSystemFile file) { static std::unordered_map<AudioSystemFile, std::wstring> const Files = { {AudioSystemFile::DefaultSound, L"ms-winsoundevent:Notification.Default" }, {AudioSystemFile::IM, L"ms-winsoundevent:Notification.IM" }, {AudioSystemFile::Mail, L"ms-winsoundevent:Notification.Mail" }, {AudioSystemFile::Reminder, L"ms-winsoundevent:Notification.Reminder" }, {AudioSystemFile::SMS, L"ms-winsoundevent:Notification.SMS" }, {AudioSystemFile::Alarm, L"ms-winsoundevent:Notification.Looping.Alarm" }, {AudioSystemFile::Alarm2, L"ms-winsoundevent:Notification.Looping.Alarm2" }, {AudioSystemFile::Alarm3, L"ms-winsoundevent:Notification.Looping.Alarm3" }, {AudioSystemFile::Alarm4, L"ms-winsoundevent:Notification.Looping.Alarm4" }, {AudioSystemFile::Alarm5, L"ms-winsoundevent:Notification.Looping.Alarm5" }, {AudioSystemFile::Alarm6, L"ms-winsoundevent:Notification.Looping.Alarm6" }, {AudioSystemFile::Alarm7, L"ms-winsoundevent:Notification.Looping.Alarm7" }, {AudioSystemFile::Alarm8, L"ms-winsoundevent:Notification.Looping.Alarm8" }, {AudioSystemFile::Alarm9, L"ms-winsoundevent:Notification.Looping.Alarm9" }, {AudioSystemFile::Alarm10, L"ms-winsoundevent:Notification.Looping.Alarm10"}, {AudioSystemFile::Call, L"ms-winsoundevent:Notification.Looping.Call" }, {AudioSystemFile::Call1, L"ms-winsoundevent:Notification.Looping.Call1" }, {AudioSystemFile::Call2, L"ms-winsoundevent:Notification.Looping.Call2" }, {AudioSystemFile::Call3, L"ms-winsoundevent:Notification.Looping.Call3" }, {AudioSystemFile::Call4, L"ms-winsoundevent:Notification.Looping.Call4" }, {AudioSystemFile::Call5, L"ms-winsoundevent:Notification.Looping.Call5" }, {AudioSystemFile::Call6, L"ms-winsoundevent:Notification.Looping.Call6" }, {AudioSystemFile::Call7, L"ms-winsoundevent:Notification.Looping.Call7" }, {AudioSystemFile::Call8, L"ms-winsoundevent:Notification.Looping.Call8" }, {AudioSystemFile::Call9, L"ms-winsoundevent:Notification.Looping.Call9" }, {AudioSystemFile::Call10, L"ms-winsoundevent:Notification.Looping.Call10" }, }; auto const iter = Files.find(file); assert(iter != Files.end()); _audioPath = iter->second; } void WinToastTemplate::setAudioOption(_In_ WinToastTemplate::AudioOption audioOption) { _audioOption = audioOption; } void WinToastTemplate::setFirstLine(_In_ std::wstring const& text) { setTextField(text, WinToastTemplate::FirstLine); } void WinToastTemplate::setSecondLine(_In_ std::wstring const& text) { setTextField(text, WinToastTemplate::SecondLine); } void WinToastTemplate::setThirdLine(_In_ std::wstring const& text) { setTextField(text, WinToastTemplate::ThirdLine); } void WinToastTemplate::setDuration(_In_ Duration duration) { _duration = duration; } void WinToastTemplate::setExpiration(_In_ INT64 millisecondsFromNow) { _expiration = millisecondsFromNow; } void WinToastLib::WinToastTemplate::setScenario(_In_ Scenario scenario) { switch (scenario) { case Scenario::Default: _scenario = L"Default"; break; case Scenario::Alarm: _scenario = L"Alarm"; break; case Scenario::IncomingCall: _scenario = L"IncomingCall"; break; case Scenario::Reminder: _scenario = L"Reminder"; break; } } void WinToastTemplate::setAttributionText(_In_ std::wstring const& attributionText) { _attributionText = attributionText; } void WinToastTemplate::addAction(_In_ std::wstring const& label) { _actions.push_back(label); } void WinToastTemplate::addInput() { _hasInput = true; } std::size_t WinToastTemplate::textFieldsCount() const { return _textFields.size(); } std::size_t WinToastTemplate::actionsCount() const { return _actions.size(); } bool WinToastTemplate::hasImage() const { return _type < WinToastTemplateType::Text01; } bool WinToastTemplate::hasHeroImage() const { return hasImage() && !_heroImagePath.empty(); } std::vector<std::wstring> const& WinToastTemplate::textFields() const { return _textFields; } std::wstring const& WinToastTemplate::textField(_In_ TextField pos) const { auto const position = static_cast<std::size_t>(pos); assert(position < _textFields.size()); return _textFields[position]; } std::wstring const& WinToastTemplate::actionLabel(_In_ std::size_t position) const { assert(position < _actions.size()); return _actions[position]; } std::wstring const& WinToastTemplate::imagePath() const { return _imagePath; } std::wstring const& WinToastTemplate::heroImagePath() const { return _heroImagePath; } std::wstring const& WinToastTemplate::audioPath() const { return _audioPath; } std::wstring const& WinToastTemplate::attributionText() const { return _attributionText; } std::wstring const& WinToastLib::WinToastTemplate::scenario() const { return _scenario; } INT64 WinToastTemplate::expiration() const { return _expiration; } WinToastTemplate::WinToastTemplateType WinToastTemplate::type() const { return _type; } WinToastTemplate::AudioOption WinToastTemplate::audioOption() const { return _audioOption; } WinToastTemplate::Duration WinToastTemplate::duration() const { return _duration; } bool WinToastTemplate::isToastGeneric() const { return hasHeroImage() || _cropHint == WinToastTemplate::Circle; } bool WinToastTemplate::isInlineHeroImage() const { return _inlineHeroImage; } bool WinToastTemplate::isCropHintCircle() const { return _cropHint == CropHint::Circle; } bool WinToastTemplate::isInput() const { return _hasInput; } 基于上述源码,新增锁屏时系统弹窗不显示在锁屏之上逻辑
10-18
程序 [csp] 注册了JDBC驱动程序 [com.alibaba.druid.proxy.DruidDriver],但在Web应用程序停止时无法注销它。 为防止内存泄漏,JDBC驱动程序已被强制取消注册。 30-Jun-2025 10:41:03.125 警告 [main] org.apache.catalina.loader.WebappClassLoaderBase.clearReferencesJdbc Web应用程序 [csp] 注册了JDBC驱动程序 [com.mysql.cj.jdbc.Driver],但在Web应用程序停止时无法注销它。 为防止内存泄漏,JDBC驱动程序已被强制取消注册。 30-Jun-2025 10:41:03.126 警告 [main] org.apache.catalina.loader.WebappClassLoaderBase.clearReferencesThreads Web应用程序[csp]似乎启动了一个名为[mysql-cj-abandoned-connection-cleanup]的线程,但未能停止它。这很可能会造成内存泄漏。线程的堆栈跟踪:[ java.lang.Object.wait(Native Method) java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:143) com.mysql.cj.jdbc.AbandonedConnectionCleanupThread.run(AbandonedConnectionCleanupThread.java:91) java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142) java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617) java.lang.Thread.run(Thread.java:745)] 30-Jun-2025 10:41:08.216 信息 [main] org.apache.catalina.startup.VersionLoggerListener.log Server.服务器版本: Apache Tomcat/9.0.106 30-Jun-2025 10:41:08.218 信息 [main] org.apache.catalina.startup.VersionLoggerListener.log 服务器构建: Jun 5 2025 19:02:30 UTC 30-Jun-2025 10:41:08.218 信息 [main] org.apache.catalina.startup.VersionLoggerListener.log 服务器版本号: 9.0.106.0 30-Jun-2025 10:41:08.218 信息 [main] org.apache.catalina.startup.VersionLoggerListener.log 操作系统名称: Linux 30-Jun-2025 10:41:08.219 信息 [main] org.apache.catalina.startup.VersionLoggerListener.log OS.版本: 3.10.0-862.el7.x86_64 30-Jun-2025 10:41:08.219 信息 [main] org.apache.catalina.startup.VersionLoggerListener.log 架构: amd64 30-Jun-2025 10:41:08.219 信息 [main] org.apache.catalina.startup.VersionLoggerListener.log Java 环境变量: /usr/local/jdk/jre 30-Jun-2025 10:41:08.219 信息 [main] org.apache.catalina.startup.VersionLoggerListener.log Java虚拟机版本: 1.8.0_44-b02 30-Jun-2025 10:41:08.219 信息 [main] org.apache.catalina.startup.VersionLoggerListener.log JVM.供应商: Oracle Corporation 30-Jun-2025 10:41:08.219 信息 [main] org.apache.catalina.startup.VersionLoggerListener.log CATALINA_BASE: /home/csp/apache-tomcat-9.0.106 30-Jun-2025 10:41:08.219 信息 [main] org.apache.catalina.startup.VersionLoggerListener.log CATALINA_HOME: /home/csp/apache-tomcat-9.0.106 30-Jun-2025 10:41:08.219 信息 [main] org.apache.catalina.startup.VersionLoggerListener.log 命令行参数: -Djava.util.logging.config.file=/home/csp/apache-tomcat-9.0.106/conf/logging.properties 30-Jun-2025 10:41:08.220 信息 [main] org.apache.catalina.startup.VersionLoggerListener.log 命令行参数: -Djava.util.logging.manager=org.apache.juli.ClassLoaderLogManager 30-Jun-2025 10:41:08.220 信息 [main] org.apache.catalina.startup.VersionLoggerListener.log 命令行参数: -Djdk.tls.ephemeralDHKeySize=2048 30-Jun-2025 10:41:08.220 信息 [main] org.apache.catalina.startup.VersionLoggerListener.log 命令行参数: -Djava.protocol.handler.pkgs=org.apache.catalina.webresources 30-Jun-2025 10:41:08.220 信息 [main] org.apache.catalina.startup.VersionLoggerListener.log 命令行参数: -Dsun.io.useCanonCaches=false 30-Jun-2025 10:41:08.220 信息 [main] org.apache.catalina.startup.VersionLoggerListener.log 命令行参数: -Dorg.apache.catalina.security.SecurityListener.UMASK=0027 30-Jun-2025 10:41:08.220 信息 [main] org.apache.catalina.startup.VersionLoggerListener.log 命令行参数: -Dignore.endorsed.dirs= 30-Jun-2025 10:41:08.220 信息 [main] org.apache.catalina.startup.VersionLoggerListener.log 命令行参数: -Dcatalina.base=/home/csp/apache-tomcat-9.0.106 30-Jun-2025 10:41:08.220 信息 [main] org.apache.catalina.startup.VersionLoggerListener.log 命令行参数: -Dcatalina.home=/home/csp/apache-tomcat-9.0.106 30-Jun-2025 10:41:08.220 信息 [main] org.apache.catalina.startup.VersionLoggerListener.log 命令行参数: -Djava.io.tmpdir=/home/csp/apache-tomcat-9.0.106/temp 30-Jun-2025 10:41:08.221 信息 [main] org.apache.catalina.core.AprLifecycleListener.lifecycleEvent 在java.library.path:[/usr/java/packages/lib/amd64:/usr/lib64:/lib64:/lib:/usr/lib]上找不到基于APR的Apache Tomcat本机库,该库允许在生产环境中获得最佳性能 30-Jun-2025 10:41:08.401 信息 [main] org.apache.coyote.AbstractProtocol.init 初始化协议处理器 ["http-nio-8080"] 30-Jun-2025 10:41:08.419 信息 [main] org.apache.catalina.startup.Catalina.load 服务器在[340]毫秒内初始化 30-Jun-2025 10:41:08.440 信息 [main] org.apache.catalina.core.StandardService.startInternal 正在启动服务[Catalina] 30-Jun-2025 10:41:08.440 信息 [main] org.apache.catalina.core.StandardEngine.startInternal 正在启动 Servlet 引擎:[Apache Tomcat/9.0.106] 30-Jun-2025 10:41:08.453 信息 [main] org.apache.catalina.startup.HostConfig.deployWAR 正在部署web应用程序存档文件[/home/csp/apache-tomcat-9.0.106/webapps/csp.war] 30-Jun-2025 10:41:12.531 信息 [main] org.apache.jasper.servlet.TldScanner.scanJars 至少有一个JAR被扫描用于TLD但尚未包含TLD。 为此记录器启用调试日志记录,以获取已扫描但未在其中找到TLD的完整JAR列表。 在扫描期间跳过不需要的JAR可以缩短启动时间和JSP编译时间。 10:41:12,573 |-INFO in ch.qos.logback.classic.LoggerContext[default] - Could NOT find resource [logback-test.xml] 10:41:12,573 |-INFO in ch.qos.logback.classic.LoggerContext[default] - Found resource [logback.xml] at [file:/home/csp/apache-tomcat-9.0.106/webapps/csp/WEB-INF/classes/logback.xml] 10:41:12,574 |-WARN in ch.qos.logback.classic.LoggerContext[default] - Resource [logback.xml] occurs multiple times on the classpath. 10:41:12,574 |-WARN in ch.qos.logback.classic.LoggerContext[default] - Resource [logback.xml] occurs at [jar:file:/home/csp/apache-tomcat-9.0.106/webapps/csp/WEB-INF/lib/client-collect-api-0.3.28.0.jar!/logback.xml] 10:41:12,574 |-WARN in ch.qos.logback.classic.LoggerContext[default] - Resource [logback.xml] occurs at [file:/home/csp/apache-tomcat-9.0.106/webapps/csp/WEB-INF/classes/logback.xml] 10:41:12,608 |-INFO in ch.qos.logback.classic.joran.action.ConfigurationAction - debug attribute not set 10:41:12,614 |-INFO in ch.qos.logback.core.joran.action.AppenderAction - About to instantiate appender of type [ch.qos.logback.core.rolling.RollingFileAppender] 10:41:12,618 |-INFO in ch.qos.logback.core.joran.action.AppenderAction - Naming appender as [FILE] 10:41:12,632 |-INFO in c.q.l.core.rolling.SizeAndTimeBasedRollingPolicy@263577281 - setting totalSizeCap to 200 GB 10:41:12,635 |-INFO in c.q.l.core.rolling.SizeAndTimeBasedRollingPolicy@263577281 - Archive files will be limited to [100 MB] each. 10:41:12,649 |-INFO in c.q.l.core.rolling.SizeAndTimeBasedRollingPolicy@263577281 - Will use gz compression 10:41:12,650 |-INFO in c.q.l.core.rolling.SizeAndTimeBasedRollingPolicy@263577281 - Will use the pattern ./logs/csp-%d{yyyy-MM-dd}.%i.log.tar for the active file 10:41:12,655 |-INFO in ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP@3e81a56b - The date pattern is 'yyyy-MM-dd' from file name pattern './logs/csp-%d{yyyy-MM-dd}.%i.log.tar.gz'. 10:41:12,655 |-INFO in ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP@3e81a56b - Roll-over at midnight. 10:41:12,655 |-INFO in ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP@3e81a56b - Setting initial period to Thu Jun 26 15:58:50 CST 2025 10:41:12,657 |-INFO in ch.qos.logback.core.joran.action.NestedComplexPropertyIA - Assuming default type [ch.qos.logback.classic.encoder.PatternLayoutEncoder] for [encoder] property 10:41:12,672 |-INFO in ch.qos.logback.core.rolling.RollingFileAppender[FILE] - Active log file name: ./logs/csp.log 10:41:12,672 |-INFO in ch.qos.logback.core.rolling.RollingFileAppender[FILE] - File property is set to [./logs/csp.log] 10:41:12,673 |-INFO in ch.qos.logback.core.joran.action.AppenderAction - About to instantiate appender of type [ch.qos.logback.core.ConsoleAppender] 10:41:12,675 |-INFO in ch.qos.logback.core.joran.action.AppenderAction - Naming appender as [STDOUT] 10:41:12,675 |-INFO in ch.qos.logback.core.joran.action.NestedComplexPropertyIA - Assuming default type [ch.qos.logback.classic.encoder.PatternLayoutEncoder] for [encoder] property 10:41:12,677 |-INFO in ch.qos.logback.classic.joran.action.LoggerAction - Setting level of logger [org.springframework] to INFO 10:41:12,677 |-INFO in ch.qos.logback.classic.joran.action.LoggerAction - Setting level of logger [springfox.documentation] to ERROR 10:41:12,677 |-INFO in ch.qos.logback.classic.joran.action.LoggerAction - Setting level of logger [org.quartz] to ERROR 10:41:12,677 |-INFO in ch.qos.logback.classic.joran.action.LoggerAction - Setting level of logger [org.mybatis] to ERROR 10:41:12,677 |-INFO in ch.qos.logback.classic.joran.action.LoggerAction - Setting level of logger [org.pbccrc] to ERROR 10:41:12,677 |-INFO in ch.qos.logback.classic.joran.action.LoggerAction - Setting level of logger [com.sine] to DEBUG 10:41:12,677 |-INFO in ch.qos.logback.classic.joran.action.LoggerAction - Setting level of logger [com.sine.csp.validate.utils] to DEBUG 10:41:12,677 |-INFO in ch.qos.logback.classic.joran.action.LoggerAction - Setting level of logger [com.sine.csp.common.dao] to ERROR 10:41:12,677 |-INFO in ch.qos.logback.classic.joran.action.LoggerAction - Setting level of logger [com.sine.csp.serviceresult.dao] to ERROR 10:41:12,677 |-INFO in ch.qos.logback.classic.joran.action.RootLoggerAction - Setting level of ROOT logger to INFO 10:41:12,677 |-INFO in ch.qos.logback.core.joran.action.AppenderRefAction - Attaching appender named [STDOUT] to Logger[ROOT] 10:41:12,678 |-INFO in ch.qos.logback.classic.joran.action.ConfigurationAction - End of configuration. 10:41:12,685 |-INFO in ch.qos.logback.classic.joran.JoranConfigurator@4bc614fc - Registering current configuration as safe fallback point . ____ _ __ _ _ /\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \ ( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \ \\/ ___)| |_)| | | | | || (_| | ) ) ) ) ' |____| .__|_| |_|_| |_\__, | / / / / =========|_|==============|___/=/_/_/_/ :: Spring Boot :: (v2.7.18) 2025-06-30 10:41:13.285 [background-preinit] INFO org.hibernate.validator.internal.util.Version - HV000001: Hibernate Validator 6.2.5.Final 2025-06-30 10:41:13.307 [main] INFO com.sine.Application - Starting Application v1.0.35-SNAPSHOT using Java 1.8.0_44 on localhost with PID 92930 (/home/csp/apache-tomcat-9.0.106/webapps/csp/WEB-INF/classes started by root in /home/csp/apache-tomcat-9.0.106/bin) 2025-06-30 10:41:13.308 [main] DEBUG com.sine.Application - Running with Spring Boot v2.7.18, Spring v5.3.39 2025-06-30 10:41:13.308 [main] INFO com.sine.Application - The following 1 profile is active: "dev" 2025-06-30 10:41:14.873 [main] INFO org.springframework.data.repository.config.RepositoryConfigurationDelegate - Multiple Spring Data modules found, entering strict repository configuration mode 2025-06-30 10:41:14.877 [main] INFO org.springframework.data.repository.config.RepositoryConfigurationDelegate - Bootstrapping Spring Data Redis repositories in DEFAULT mode. 2025-06-30 10:41:14.945 [main] INFO org.springframework.data.repository.config.RepositoryConfigurationDelegate - Finished Spring Data repository scanning in 51 ms. Found 0 Redis repository interfaces. 2025-06-30 10:41:15.963 [main] INFO org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext - Root WebApplicationContext: initialization completed in 2629 ms 2025-06-30 10:41:16.575 [main] INFO org.springframework.boot.web.servlet.RegistrationBean - Filter xssFilter was not registered (possibly already registered?) 2025-06-30 10:41:17.892 [main] INFO com.alibaba.druid.pool.DruidDataSource - {dataSource-1} inited 2025-06-30 10:41:20.438 [main] INFO org.springframework.scheduling.quartz.LocalDataSourceJobStore - Using db table-based data access locking (synchronization). 2025-06-30 10:41:20.439 [main] INFO org.springframework.scheduling.quartz.LocalDataSourceJobStore - JobStoreCMT initialized. 2025-06-30 10:41:21.526 [main] INFO org.springframework.aop.framework.CglibAopProxy - Unable to proxy interface-implementing method [public final void org.springframework.scheduling.quartz.QuartzJobBean.execute(org.quartz.JobExecutionContext) throws org.quartz.JobExecutionException] because it is marked as final: Consider using interface-based JDK proxies instead! 2025-06-30 10:41:21.528 [main] INFO org.springframework.aop.framework.CglibAopProxy - Unable to proxy interface-implementing method [public final void org.springframework.scheduling.quartz.QuartzJobBean.execute(org.quartz.JobExecutionContext) throws org.quartz.JobExecutionException] because it is marked as final: Consider using interface-based JDK proxies instead! 2025-06-30 10:41:21.531 [main] INFO org.springframework.aop.framework.CglibAopProxy - Unable to proxy interface-implementing method [public final void org.springframework.scheduling.quartz.QuartzJobBean.execute(org.quartz.JobExecutionContext) throws org.quartz.JobExecutionException] because it is marked as final: Consider using interface-based JDK proxies instead! 2025-06-30 10:41:21.829 [main] INFO org.springframework.aop.framework.CglibAopProxy - Unable to proxy interface-implementing method [public final void org.springframework.scheduling.quartz.QuartzJobBean.execute(org.quartz.JobExecutionContext) throws org.quartz.JobExecutionException] because it is marked as final: Consider using interface-based JDK proxies instead! 2025-06-30 10:41:21.839 [main] INFO org.springframework.aop.framework.CglibAopProxy - Unable to proxy interface-implementing method [public final void org.springframework.scheduling.quartz.QuartzJobBean.execute(org.quartz.JobExecutionContext) throws org.quartz.JobExecutionException] because it is marked as final: Consider using interface-based JDK proxies instead! 2025-06-30 10:41:21.843 [main] INFO org.springframework.aop.framework.CglibAopProxy - Unable to proxy interface-implementing method [public final void org.springframework.scheduling.quartz.QuartzJobBean.execute(org.quartz.JobExecutionContext) throws org.quartz.JobExecutionException] because it is marked as final: Consider using interface-based JDK proxies instead! 2025-06-30 10:41:22.696 [main] WARN org.thymeleaf.templatemode.TemplateMode - [THYMELEAF][main] Template Mode 'HTML5' is deprecated. Using Template Mode 'HTML' instead. 2025-06-30 10:41:23.124 [main] INFO org.springframework.boot.actuate.endpoint.web.EndpointLinksResolver - Exposing 0 endpoint(s) beneath base path '/actuator' 2025-06-30 10:41:23.164 [main] INFO org.springframework.scheduling.quartz.SchedulerFactoryBean - Starting Quartz Scheduler now 2025-06-30 10:41:24.144 [main] INFO com.sine.Application - Started Application in 11.303 seconds (JVM running for 16.22) 2025-06-30 10:41:24.458 [main] INFO org.springframework.boot.autoconfigure.logging.ConditionEvaluationReportLoggingListener - Error starting ApplicationContext. To display the conditions report re-run your application with 'debug' enabled. 2025-06-30 10:41:24.486 [main] ERROR org.springframework.boot.SpringApplication - Application run failed java.lang.IllegalStateException: Failed to execute ApplicationRunner at org.springframework.boot.SpringApplication.callRunner(SpringApplication.java:759) at org.springframework.boot.SpringApplication.lambda$callRunners$2(SpringApplication.java:746) at org.springframework.boot.SpringApplication$$Lambda$1079/1133797119.accept(Unknown Source) at java.util.stream.ForEachOps$ForEachOp$OfRef.accept(ForEachOps.java:184) at java.util.stream.SortedOps$SizedRefSortingSink.end(SortedOps.java:352) at java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:513) at java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:502) at java.util.stream.ForEachOps$ForEachOp.evaluateSequential(ForEachOps.java:151) at java.util.stream.ForEachOps$ForEachOp$OfRef.evaluateSequential(ForEachOps.java:174) at java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:234) at java.util.stream.ReferencePipeline.forEach(ReferencePipeline.java:418) at org.springframework.boot.SpringApplication.callRunners(SpringApplication.java:744) at org.springframework.boot.SpringApplication.run(SpringApplication.java:315) at org.springframework.boot.web.servlet.support.SpringBootServletInitializer.run(SpringBootServletInitializer.java:175) at org.springframework.boot.web.servlet.support.SpringBootServletInitializer.createRootApplicationContext(SpringBootServletInitializer.java:155) at org.springframework.boot.web.servlet.support.SpringBootServletInitializer.onStartup(SpringBootServletInitializer.java:97) at org.springframework.web.SpringServletContainerInitializer.onStartup(SpringServletContainerInitializer.java:174) at org.apache.catalina.core.StandardContext.startInternal(StandardContext.java:4491) at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:164) at org.apache.catalina.core.ContainerBase.addChildInternal(ContainerBase.java:599) at org.apache.catalina.core.ContainerBase.addChild(ContainerBase.java:571) at org.apache.catalina.core.StandardHost.addChild(StandardHost.java:603) at org.apache.catalina.startup.HostConfig.deployWAR(HostConfig.java:1013) at org.apache.catalina.startup.HostConfig$DeployWar.run(HostConfig.java:1861) at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511) at java.util.concurrent.FutureTask.run(FutureTask.java:266) at org.apache.tomcat.util.threads.InlineExecutorService.execute(InlineExecutorService.java:76) at java.util.concurrent.AbstractExecutorService.submit(AbstractExecutorService.java:112) at org.apache.catalina.startup.HostConfig.deployWARs(HostConfig.java:817) at org.apache.catalina.startup.HostConfig.deployApps(HostConfig.java:468) at org.apache.catalina.startup.HostConfig.start(HostConfig.java:1579) at org.apache.catalina.startup.HostConfig.lifecycleEvent(HostConfig.java:312) at org.apache.catalina.util.LifecycleBase.fireLifecycleEvent(LifecycleBase.java:109) at org.apache.catalina.util.LifecycleBase.setStateInternal(LifecycleBase.java:389) at org.apache.catalina.util.LifecycleBase.setState(LifecycleBase.java:336) at org.apache.catalina.core.ContainerBase.startInternal(ContainerBase.java:776) at org.apache.catalina.core.StandardHost.startInternal(StandardHost.java:721) at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:164) at org.apache.catalina.core.ContainerBase$StartChild.call(ContainerBase.java:1203) at org.apache.catalina.core.ContainerBase$StartChild.call(ContainerBase.java:1193) at java.util.concurrent.FutureTask.run(FutureTask.java:266) at org.apache.tomcat.util.threads.InlineExecutorService.execute(InlineExecutorService.java:76) at java.util.concurrent.AbstractExecutorService.submit(AbstractExecutorService.java:134) at org.apache.catalina.core.ContainerBase.startInternal(ContainerBase.java:749) at org.apache.catalina.core.StandardEngine.startInternal(StandardEngine.java:211) at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:164) at org.apache.catalina.core.StandardService.startInternal(StandardService.java:412) at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:164) at org.apache.catalina.core.StandardServer.startInternal(StandardServer.java:874) at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:164) at org.apache.catalina.startup.Catalina.start(Catalina.java:739) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) at java.lang.reflect.Method.invoke(Method.java:497) at org.apache.catalina.startup.Bootstrap.start(Bootstrap.java:345) at org.apache.catalina.startup.Bootstrap.main(Bootstrap.java:476) Caused by: org.springframework.data.redis.RedisConnectionFailureException: Unable to connect to Redis; nested exception is org.springframework.data.redis.connection.PoolException: Could not get a resource from the pool; nested exception is io.lettuce.core.RedisConnectionException: Unable to connect to 127.0.0.1:6379 at org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory$ExceptionTranslatingConnectionProvider.translateException(LettuceConnectionFactory.java:1689) at org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory$ExceptionTranslatingConnectionProvider.getConnection(LettuceConnectionFactory.java:1597) at org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory$SharedConnection.getNativeConnection(LettuceConnectionFactory.java:1383) at org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory$SharedConnection.getConnection(LettuceConnectionFactory.java:1366) at org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory.getSharedConnection(LettuceConnectionFactory.java:1093) at org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory.getConnection(LettuceConnectionFactory.java:421) at org.springframework.data.redis.core.RedisConnectionUtils.fetchConnection(RedisConnectionUtils.java:193) at org.springframework.data.redis.core.RedisConnectionUtils.doGetConnection(RedisConnectionUtils.java:144) at org.springframework.data.redis.core.RedisConnectionUtils.getConnection(RedisConnectionUtils.java:105) at org.springframework.data.redis.core.RedisTemplate.execute(RedisTemplate.java:211) at org.springframework.data.redis.core.RedisTemplate.execute(RedisTemplate.java:191) at org.springframework.data.redis.core.RedisTemplate.keys(RedisTemplate.java:896) at com.sine.csp.common.boot.RedisCleanService.run(RedisCleanService.java:27) at org.springframework.boot.SpringApplication.callRunner(SpringApplication.java:756) ... 56 common frames omitted Caused by: org.springframework.data.redis.connection.PoolException: Could not get a resource from the pool; nested exception is io.lettuce.core.RedisConnectionException: Unable to connect to 127.0.0.1:6379 at org.springframework.data.redis.connection.lettuce.LettucePoolingConnectionProvider.getConnection(LettucePoolingConnectionProvider.java:109) at org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory$ExceptionTranslatingConnectionProvider.getConnection(LettuceConnectionFactory.java:1595) ... 68 common frames omitted Caused by: io.lettuce.core.RedisConnectionException: Unable to connect to 127.0.0.1:6379 at io.lettuce.core.RedisConnectionException.create(RedisConnectionException.java:78) at io.lettuce.core.RedisConnectionException.create(RedisConnectionException.java:56) at io.lettuce.core.AbstractRedisClient.getConnection(AbstractRedisClient.java:330) at io.lettuce.core.RedisClient.connect(RedisClient.java:216) at org.springframework.data.redis.connection.lettuce.StandaloneConnectionProvider.lambda$getConnection$1(StandaloneConnectionProvider.java:115) at org.springframework.data.redis.connection.lettuce.StandaloneConnectionProvider$$Lambda$1084/1822563181.get(Unknown Source) at java.util.Optional.orElseGet(Optional.java:267) at org.springframework.data.redis.connection.lettuce.StandaloneConnectionProvider.getConnection(StandaloneConnectionProvider.java:115) at org.springframework.data.redis.connection.lettuce.LettucePoolingConnectionProvider.lambda$null$0(LettucePoolingConnectionProvider.java:97) at org.springframework.data.redis.connection.lettuce.LettucePoolingConnectionProvider$$Lambda$1082/1664936139.get(Unknown Source) at io.lettuce.core.support.ConnectionPoolSupport$RedisPooledObjectFactory.create(ConnectionPoolSupport.java:211) at io.lettuce.core.support.ConnectionPoolSupport$RedisPooledObjectFactory.create(ConnectionPoolSupport.java:201) at org.apache.commons.pool2.BasePooledObjectFactory.makeObject(BasePooledObjectFactory.java:70) at org.apache.commons.pool2.impl.GenericObjectPool.create(GenericObjectPool.java:571) at org.apache.commons.pool2.impl.GenericObjectPool.borrowObject(GenericObjectPool.java:298) at org.apache.commons.pool2.impl.GenericObjectPool.borrowObject(GenericObjectPool.java:223) at io.lettuce.core.support.ConnectionPoolSupport$1.borrowObject(ConnectionPoolSupport.java:122) at io.lettuce.core.support.ConnectionPoolSupport$1.borrowObject(ConnectionPoolSupport.java:117) at org.springframework.data.redis.connection.lettuce.LettucePoolingConnectionProvider.getConnection(LettucePoolingConnectionProvider.java:103) ... 69 common frames omitted Caused by: io.lettuce.core.RedisCommandExecutionException: NOAUTH HELLO must be called with the client already authenticated, otherwise the HELLO AUTH <user> <pass> option can be used to authenticate the client and select the RESP protocol version at the same time at io.lettuce.core.internal.ExceptionFactory.createExecutionException(ExceptionFactory.java:147) at io.lettuce.core.internal.ExceptionFactory.createExecutionException(ExceptionFactory.java:116) at io.lettuce.core.protocol.AsyncCommand.completeResult(AsyncCommand.java:120) at io.lettuce.core.protocol.AsyncCommand.complete(AsyncCommand.java:111) at io.lettuce.core.protocol.CommandWrapper.complete(CommandWrapper.java:63) at io.lettuce.core.protocol.CommandHandler.complete(CommandHandler.java:747) at io.lettuce.core.protocol.CommandHandler.decode(CommandHandler.java:682) at io.lettuce.core.protocol.CommandHandler.channelRead(CommandHandler.java:599) at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:442) at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:420) at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:412) at io.netty.channel.DefaultChannelPipeline$HeadContext.channelRead(DefaultChannelPipeline.java:1410) at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:440) at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:420) at io.netty.channel.DefaultChannelPipeline.fireChannelRead(DefaultChannelPipeline.java:919) at io.netty.channel.epoll.AbstractEpollStreamChannel$EpollStreamUnsafe.epollInReady(AbstractEpollStreamChannel.java:800) at io.netty.channel.epoll.EpollEventLoop.processReady(EpollEventLoop.java:509) at io.netty.channel.epoll.EpollEventLoop.run(EpollEventLoop.java:407) at io.netty.util.concurrent.SingleThreadEventExecutor$4.run(SingleThreadEventExecutor.java:997) at io.netty.util.internal.ThreadExecutorMap$2.run(ThreadExecutorMap.java:74) at io.netty.util.concurrent.FastThreadLocalRunnable.run(FastThreadLocalRunnable.java:30) at java.lang.Thread.run(Thread.java:745) 2025-06-30 10:41:24.514 [main] INFO org.springframework.scheduling.quartz.SchedulerFactoryBean - Shutting down Quartz Scheduler 2025-06-30 10:41:25.601 [main] INFO com.alibaba.druid.pool.DruidDataSource - {dataSource-1} closing ... 2025-06-30 10:41:25.616 [main] INFO com.alibaba.druid.pool.DruidDataSource - {dataSource-1} closed 30-Jun-2025 10:41:25.621 严重 [main] org.apache.catalina.startup.HostConfig.deployWAR 部署 Web 应用程序 archive [/home/csp/apache-tomcat-9.0.106/webapps/csp.war] 时出错 java.lang.IllegalStateException: 启动子级时出错 at org.apache.catalina.core.ContainerBase.addChildInternal(ContainerBase.java:602) at org.apache.catalina.core.ContainerBase.addChild(ContainerBase.java:571) at org.apache.catalina.core.StandardHost.addChild(StandardHost.java:603) at org.apache.catalina.startup.HostConfig.deployWAR(HostConfig.java:1013) at org.apache.catalina.startup.HostConfig$DeployWar.run(HostConfig.java:1861) at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511) at java.util.concurrent.FutureTask.run(FutureTask.java:266) at org.apache.tomcat.util.threads.InlineExecutorService.execute(InlineExecutorService.java:76) at java.util.concurrent.AbstractExecutorService.submit(AbstractExecutorService.java:112) at org.apache.catalina.startup.HostConfig.deployWARs(HostConfig.java:817) at org.apache.catalina.startup.HostConfig.deployApps(HostConfig.java:468) at org.apache.catalina.startup.HostConfig.start(HostConfig.java:1579) at org.apache.catalina.startup.HostConfig.lifecycleEvent(HostConfig.java:312) at org.apache.catalina.util.LifecycleBase.fireLifecycleEvent(LifecycleBase.java:109) at org.apache.catalina.util.LifecycleBase.setStateInternal(LifecycleBase.java:389) at org.apache.catalina.util.LifecycleBase.setState(LifecycleBase.java:336) at org.apache.catalina.core.ContainerBase.startInternal(ContainerBase.java:776) at org.apache.catalina.core.StandardHost.startInternal(StandardHost.java:721) at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:164) at org.apache.catalina.core.ContainerBase$StartChild.call(ContainerBase.java:1203) at org.apache.catalina.core.ContainerBase$StartChild.call(ContainerBase.java:1193) at java.util.concurrent.FutureTask.run(FutureTask.java:266) at org.apache.tomcat.util.threads.InlineExecutorService.execute(InlineExecutorService.java:76) at java.util.concurrent.AbstractExecutorService.submit(AbstractExecutorService.java:134) at org.apache.catalina.core.ContainerBase.startInternal(ContainerBase.java:749) at org.apache.catalina.core.StandardEngine.startInternal(StandardEngine.java:211) at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:164) at org.apache.catalina.core.StandardService.startInternal(StandardService.java:412) at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:164) at org.apache.catalina.core.StandardServer.startInternal(StandardServer.java:874) at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:164) at org.apache.catalina.startup.Catalina.start(Catalina.java:739) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) at java.lang.reflect.Method.invoke(Method.java:497) at org.apache.catalina.startup.Bootstrap.start(Bootstrap.java:345) at org.apache.catalina.startup.Bootstrap.main(Bootstrap.java:476) Caused by: org.apache.catalina.LifecycleException: 无法启动组件[StandardEngine[Catalina].StandardHost[localhost].StandardContext[/csp]] at org.apache.catalina.util.LifecycleBase.handleSubClassException(LifecycleBase.java:406) at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:179) at org.apache.catalina.core.ContainerBase.addChildInternal(ContainerBase.java:599) ... 37 more Caused by: java.lang.IllegalStateException: Failed to execute ApplicationRunner at org.springframework.boot.SpringApplication.callRunner(SpringApplication.java:759) at org.springframework.boot.SpringApplication.lambda$callRunners$2(SpringApplication.java:746) at org.springframework.boot.SpringApplication$$Lambda$1079/1133797119.accept(Unknown Source) at java.util.stream.ForEachOps$ForEachOp$OfRef.accept(ForEachOps.java:184) at java.util.stream.SortedOps$SizedRefSortingSink.end(SortedOps.java:352) at java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:513) at java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:502) at java.util.stream.ForEachOps$ForEachOp.evaluateSequential(ForEachOps.java:151) at java.util.stream.ForEachOps$ForEachOp$OfRef.evaluateSequential(ForEachOps.java:174) at java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:234) at java.util.stream.ReferencePipeline.forEach(ReferencePipeline.java:418) at org.springframework.boot.SpringApplication.callRunners(SpringApplication.java:744) at org.springframework.boot.SpringApplication.run(SpringApplication.java:315) at org.springframework.boot.web.servlet.support.SpringBootServletInitializer.run(SpringBootServletInitializer.java:175) at org.springframework.boot.web.servlet.support.SpringBootServletInitializer.createRootApplicationContext(SpringBootServletInitializer.java:155) at org.springframework.boot.web.servlet.support.SpringBootServletInitializer.onStartup(SpringBootServletInitializer.java:97) at org.springframework.web.SpringServletContainerInitializer.onStartup(SpringServletContainerInitializer.java:174) at org.apache.catalina.core.StandardContext.startInternal(StandardContext.java:4491) at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:164) ... 38 more Caused by: org.springframework.data.redis.RedisConnectionFailureException: Unable to connect to Redis; nested exception is org.springframework.data.redis.connection.PoolException: Could not get a resource from the pool; nested exception is io.lettuce.core.RedisConnectionException: Unable to connect to 127.0.0.1:6379 at org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory$ExceptionTranslatingConnectionProvider.translateException(LettuceConnectionFactory.java:1689) at org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory$ExceptionTranslatingConnectionProvider.getConnection(LettuceConnectionFactory.java:1597) at org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory$SharedConnection.getNativeConnection(LettuceConnectionFactory.java:1383) at org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory$SharedConnection.getConnection(LettuceConnectionFactory.java:1366) at org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory.getSharedConnection(LettuceConnectionFactory.java:1093) at org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory.getConnection(LettuceConnectionFactory.java:421) at org.springframework.data.redis.core.RedisConnectionUtils.fetchConnection(RedisConnectionUtils.java:193) at org.springframework.data.redis.core.RedisConnectionUtils.doGetConnection(RedisConnectionUtils.java:144) at org.springframework.data.redis.core.RedisConnectionUtils.getConnection(RedisConnectionUtils.java:105) at org.springframework.data.redis.core.RedisTemplate.execute(RedisTemplate.java:211) at org.springframework.data.redis.core.RedisTemplate.execute(RedisTemplate.java:191) at org.springframework.data.redis.core.RedisTemplate.keys(RedisTemplate.java:896) at com.sine.csp.common.boot.RedisCleanService.run(RedisCleanService.java:27) at org.springframework.boot.SpringApplication.callRunner(SpringApplication.java:756) ... 56 more Caused by: org.springframework.data.redis.connection.PoolException: Could not get a resource from the pool; nested exception is io.lettuce.core.RedisConnectionException: Unable to connect to 127.0.0.1:6379 at org.springframework.data.redis.connection.lettuce.LettucePoolingConnectionProvider.getConnection(LettucePoolingConnectionProvider.java:109) at org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory$ExceptionTranslatingConnectionProvider.getConnection(LettuceConnectionFactory.java:1595) ... 68 more Caused by: io.lettuce.core.RedisConnectionException: Unable to connect to 127.0.0.1:6379 at io.lettuce.core.RedisConnectionException.create(RedisConnectionException.java:78) at io.lettuce.core.RedisConnectionException.create(RedisConnectionException.java:56) at io.lettuce.core.AbstractRedisClient.getConnection(AbstractRedisClient.java:330) at io.lettuce.core.RedisClient.connect(RedisClient.java:216) at org.springframework.data.redis.connection.lettuce.StandaloneConnectionProvider.lambda$getConnection$1(StandaloneConnectionProvider.java:115) at org.springframework.data.redis.connection.lettuce.StandaloneConnectionProvider$$Lambda$1084/1822563181.get(Unknown Source) at java.util.Optional.orElseGet(Optional.java:267) at org.springframework.data.redis.connection.lettuce.StandaloneConnectionProvider.getConnection(StandaloneConnectionProvider.java:115) at org.springframework.data.redis.connection.lettuce.LettucePoolingConnectionProvider.lambda$null$0(LettucePoolingConnectionProvider.java:97) at org.springframework.data.redis.connection.lettuce.LettucePoolingConnectionProvider$$Lambda$1082/1664936139.get(Unknown Source) at io.lettuce.core.support.ConnectionPoolSupport$RedisPooledObjectFactory.create(ConnectionPoolSupport.java:211) at io.lettuce.core.support.ConnectionPoolSupport$RedisPooledObjectFactory.create(ConnectionPoolSupport.java:201) at org.apache.commons.pool2.BasePooledObjectFactory.makeObject(BasePooledObjectFactory.java:70) at org.apache.commons.pool2.impl.GenericObjectPool.create(GenericObjectPool.java:571) at org.apache.commons.pool2.impl.GenericObjectPool.borrowObject(GenericObjectPool.java:298) at org.apache.commons.pool2.impl.GenericObjectPool.borrowObject(GenericObjectPool.java:223) at io.lettuce.core.support.ConnectionPoolSupport$1.borrowObject(ConnectionPoolSupport.java:122) at io.lettuce.core.support.ConnectionPoolSupport$1.borrowObject(ConnectionPoolSupport.java:117) at org.springframework.data.redis.connection.lettuce.LettucePoolingConnectionProvider.getConnection(LettucePoolingConnectionProvider.java:103) ... 69 more Caused by: io.lettuce.core.RedisCommandExecutionException: NOAUTH HELLO must be called with the client already authenticated, otherwise the HELLO AUTH <user> <pass> option can be used to authenticate the client and select the RESP protocol version at the same time at io.lettuce.core.internal.ExceptionFactory.createExecutionException(ExceptionFactory.java:147) at io.lettuce.core.internal.ExceptionFactory.createExecutionException(ExceptionFactory.java:116) at io.lettuce.core.protocol.AsyncCommand.completeResult(AsyncCommand.java:120) at io.lettuce.core.protocol.AsyncCommand.complete(AsyncCommand.java:111) at io.lettuce.core.protocol.CommandWrapper.complete(CommandWrapper.java:63) at io.lettuce.core.protocol.CommandHandler.complete(CommandHandler.java:747) at io.lettuce.core.protocol.CommandHandler.decode(CommandHandler.java:682) at io.lettuce.core.protocol.CommandHandler.channelRead(CommandHandler.java:599) at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:442) at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:420) at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:412) at io.netty.channel.DefaultChannelPipeline$HeadContext.channelRead(DefaultChannelPipeline.java:1410) at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:440) at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:420) at io.netty.channel.DefaultChannelPipeline.fireChannelRead(DefaultChannelPipeline.java:919) at io.netty.channel.epoll.AbstractEpollStreamChannel$EpollStreamUnsafe.epollInReady(AbstractEpollStreamChannel.java:800) at io.netty.channel.epoll.EpollEventLoop.processReady(EpollEventLoop.java:509) at io.netty.channel.epoll.EpollEventLoop.run(EpollEventLoop.java:407) at io.netty.util.concurrent.SingleThreadEventExecutor$4.run(SingleThreadEventExecutor.java:997) at io.netty.util.internal.ThreadExecutorMap$2.run(ThreadExecutorMap.java:74) at io.netty.util.concurrent.FastThreadLocalRunnable.run(FastThreadLocalRunnable.java:30) at java.lang.Thread.run(Thread.java:745) 30-Jun-2025 10:41:25.637 信息 [main] org.apache.catalina.startup.HostConfig.deployWAR web应用程序存档文件[/home/csp/apache-tomcat-9.0.106/webapps/csp.war]的部署已在[17,181]ms内完成 30-Jun-2025 10:41:25.637 信息 [main] org.apache.catalina.startup.HostConfig.deployDirectory 把web 应用程序部署到目录 [/home/csp/apache-tomcat-9.0.106/webapps/ROOT] 30-Jun-2025 10:41:25.659 信息 [main] org.apache.catalina.startup.HostConfig.deployDirectory Web应用程序目录[/home/csp/apache-tomcat-9.0.106/webapps/ROOT]的部署已在[22]毫秒内完成 30-Jun-2025 10:41:25.659 信息 [main] org.apache.catalina.startup.HostConfig.deployDirectory 把web 应用程序部署到目录 [/home/csp/apache-tomcat-9.0.106/webapps/docs] 30-Jun-2025 10:41:25.672 信息 [main] org.apache.catalina.startup.HostConfig.deployDirectory Web应用程序目录[/home/csp/apache-tomcat-9.0.106/webapps/docs]的部署已在[12]毫秒内完成 30-Jun-2025 10:41:25.672 信息 [main] org.apache.catalina.startup.HostConfig.deployDirectory 把web 应用程序部署到目录 [/home/csp/apache-tomcat-9.0.106/webapps/examples] 30-Jun-2025 10:41:25.770 信息 [main] org.apache.catalina.startup.HostConfig.deployDirectory Web应用程序目录[/home/csp/apache-tomcat-9.0.106/webapps/examples]的部署已在[97]毫秒内完成 30-Jun-2025 10:41:25.770 信息 [main] org.apache.catalina.startup.HostConfig.deployDirectory 把web 应用程序部署到目录 [/home/csp/apache-tomcat-9.0.106/webapps/host-manager] 30-Jun-2025 10:41:25.782 信息 [main] org.apache.catalina.startup.HostConfig.deployDirectory Web应用程序目录[/home/csp/apache-tomcat-9.0.106/webapps/host-manager]的部署已在[12]毫秒内完成 30-Jun-2025 10:41:25.783 信息 [main] org.apache.catalina.startup.HostConfig.deployDirectory 把web 应用程序部署到目录 [/home/csp/apache-tomcat-9.0.106/webapps/manager] 30-Jun-2025 10:41:25.805 信息 [main] org.apache.catalina.startup.HostConfig.deployDirectory Web应用程序目录[/home/csp/apache-tomcat-9.0.106/webapps/manager]的部署已在[23]毫秒内完成 30-Jun-2025 10:41:25.809 信息 [main] org.apache.coyote.AbstractProtocol.start 开始协议处理句柄["http-nio-8080"] 30-Jun-2025 10:41:25.836 信息 [main] org.apache.catalina.startup.Catalina.start [17417]毫秒后服务器启动 30-Jun-2025 10:41:29.190 警告 [http-nio-8080-exec-3] org.apache.catalina.loader.WebappClassLoaderBase.clearReferencesJdbc Web应用程序 [csp] 注册了JDBC驱动程序 [com.alibaba.druid.proxy.DruidDriver],但在Web应用程序停止时无法注销它。 为防止内存泄漏,JDBC驱动程序已被强制取消注册。 30-Jun-2025 10:41:29.191 警告 [http-nio-8080-exec-3] org.apache.catalina.loader.WebappClassLoaderBase.clearReferencesJdbc Web应用程序 [csp] 注册了JDBC驱动程序 [com.mysql.cj.jdbc.Driver],但在Web应用程序停止时无法注销它。 为防止内存泄漏,JDBC驱动程序已被强制取消注册。 30-Jun-2025 10:41:29.193 警告 [http-nio-8080-exec-3] org.apache.catalina.loader.WebappClassLoaderBase.clearReferencesThreads Web应用程序[csp]似乎启动了一个名为[mysql-cj-abandoned-connection-cleanup]的线程,但未能停止它。这很可能会造成内存泄漏。线程的堆栈跟踪:[ java.lang.Object.wait(Native Method) java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:143) com.mysql.cj.jdbc.AbandonedConnectionCleanupThread.run(AbandonedConnectionCleanupThread.java:91) java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142) java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617) java.lang.Thread.run(Thread.java:745)] 30-Jun-2025 10:41:29.194 严重 [http-nio-8080-exec-3] org.apache.catalina.loader.WebappClassLoaderBase.checkThreadLocalMapForLeaks web应用程序[csp]创建了一个ThreadLocal,其键类型为[org.springframework.boot.SpringBootExceptionHandler.LoggedExceptionHandlerThreadLocal](值为[org.springframework.boot.SpringBootExceptionHandler$LoggedExceptionHandlerThreadLocal@284f8fa0]),值类型为[org.springframework.boot.SpringBootExceptionHandler](值为[org.springframework.boot.SpringBootExceptionHandler@4a632f7c),但在停止web应用程序时未能将其删除。线程将随着时间的推移而更新,以尝试避免可能的内存泄漏 30-Jun-2025 10:41:29.194 严重 [http-nio-8080-exec-3] org.apache.catalina.loader.WebappClassLoaderBase.checkThreadLocalMapForLeaks web应用程序[csp]创建了一个ThreadLocal,其键类型为[java.lang.ThreadLocal](值为[java.lang.ThreadLocal@40ba36e7]),值类型为[io.netty.util.internal.InternalThreadLocalMap](值为[io.netty.util.internal.InternalThreadLocalMap@6ad179a0),但在停止web应用程序时未能将其删除。线程将随着时间的推移而更新,以尝试避免可能的内存泄漏 30-Jun-2025 10:41:29.995 信息 [mysql-cj-abandoned-connection-cleanup] org.apache.catalina.loader.WebappClassLoaderBase.checkStateForResourceLoading 非法访问:此Web应用程序实例已停止。无法加载[]。为了调试以及终止导致非法访问的线程,将抛出以下堆栈跟踪。 java.lang.IllegalStateException: 非法访问:此Web应用程序实例已停止。无法加载[]。为了调试以及终止导致非法访问的线程,将抛出以下堆栈跟踪。 at org.apache.catalina.loader.WebappClassLoaderBase.checkStateForResourceLoading(WebappClassLoaderBase.java:1374) at org.apache.catalina.loader.WebappClassLoaderBase.getResource(WebappClassLoaderBase.java:997) at com.mysql.cj.jdbc.AbandonedConnectionCleanupThread.checkThreadContextClassLoader(AbandonedConnectionCleanupThread.java:123) at com.mysql.cj.jdbc.AbandonedConnectionCleanupThread.run(AbandonedConnectionCleanupThread.java:90) at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142) at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617) at java.lang.Thread.run(Thread.java:745) 30-Jun-2025 10:41:32.509 信息 [http-nio-8080-exec-3] org.apache.jasper.servlet.TldScanner.scanJars 至少有一个JAR被扫描用于TLD但尚未包含TLD。 为此记录器启用调试日志记录,以获取已扫描但未在其中找到TLD的完整JAR列表。 在扫描期间跳过不需要的JAR可以缩短启动时间和JSP编译时间。
07-01
#include <pigpio.h> #include <iostream> #include <unistd.h> #include <opencv2/opencv.hpp> #include <vector> #include <string> #include <tensorflow/lite/interpreter.h> #include <tensorflow/lite/model.h> #include <tensorflow/lite/kernels/register.h> #include <fstream> #include <nlohmann/json.hpp> using namespace cv; using namespace std; using json = nlohmann::json; // ---------- 配置参数 ---------- const int pwm_pin = 13; const int servo_pin = 12; const int pwm_freq1 = 200; const int pwm_freq2 = 50; const int pwm_range1 = 40000; const int pwm_range2 = 100; const int init_duty = 10000; double last_error = 0; const double kp = 0.3, kd = 0.08; const double min_ang = 70, max_ang = 94; bool debug_save = true; bool ab_detected = false; int detected_letter = 0; int action_cooldown = 0; // ---------- TensorFlow Lite模型类 ---------- class TFLiteModel { private: std::unique_ptr<tflite::FlatBufferModel> model; std::unique_ptr<tflite::Interpreter> interpreter; std::vector<std::string> classLabels; bool modelLoaded; public: TFLiteModel() : modelLoaded(false) {} bool loadModel(const std::string& model_path) { // 加载TensorFlow Lite模型 model = tflite::FlatBufferModel::BuildFromFile(model_path.c_str()); if (!model) { std::cerr << "Failed to load model: " << model_path << std::endl; return false; } // 创建解释器 tflite::ops::builtin::BuiltinOpResolver resolver; tflite::InterpreterBuilder(*model, resolver)(&interpreter); if (!interpreter) { std::cerr << "Failed to create interpreter" << std::endl; return false; } // 分配张量 if (interpreter->AllocateTensors() != kTfLiteOk) { std::cerr << "Failed to allocate tensors" << std::endl; return false; } modelLoaded = true; std::cout << "TFLite model loaded successfully" << std::endl; return true; } bool loadLabels(const std::string& label_path) { std::ifstream file(label_path); if (!file.is_open()) { std::cerr << "Failed to open labels file: " << label_path << std::endl; return false; } try { json j; file >> j; // 从JSON文件读取类别映射 for (auto& element : j.items()) { int index = element.value(); std::string label = element.key(); // 确保vector足够大 if (index >= classLabels.size()) { classLabels.resize(index + 1); } classLabels[index] = label; } std::cout << "Labels loaded (" << classLabels.size() << " classes): "; for (size_t i = 0; i < classLabels.size(); ++i) { if (!classLabels[i].empty()) { std::cout << i << "->" << classLabels[i] << " "; } } std::cout << std::endl; return true; } catch (const std::exception& e) { std::cerr << "Error parsing labels file: " << e.what() << std::endl; return false; } } std::string classify(const Mat& image, float& confidence) { if (!modelLoaded || classLabels.empty()) { confidence = 0.0f; return "error"; } // 预处理图像 - 调整为模型期望的输入尺寸 Mat processed; resize(image, processed, Size(128, 128)); // 根据你的模型输入尺寸调整 // 转换颜色空间 BGR -> RGB cvtColor(processed, processed, COLOR_BGR2RGB); // 归一化到 [0,1] processed.convertTo(processed, CV_32FC3, 1.0/255.0); // 获取输入张量 float* input = interpreter->typed_input_tensor<float>(0); // 将图像数据复制到输入张量 if (processed.isContinuous()) { std::memcpy(input, processed.data, processed.total() * processed.elemSize()); } else { std::cerr << "Image data is not continuous" << std::endl; confidence = 0.0f; return "error"; } // 运行推理 if (interpreter->Invoke() != kTfLiteOk) { std::cerr << "Failed to invoke interpreter" << std::endl; confidence = 0.0f; return "error"; } // 获取输出张量 float* output = interpreter->typed_output_tensor<float>(0); int output_size = interpreter->output_tensor(0)->dims->data[1]; // 找到最大概率的类别 int max_index = 0; float max_prob = output[0]; for (int i = 1; i < output_size; ++i) { if (output[i] > max_prob) { max_prob = output[i]; max_index = i; } } confidence = max_prob; // 返回类别名称 if (max_index < classLabels.size() && !classLabels[max_index].empty()) { std::cout << "Model prediction: " << classLabels[max_index] << " Confidence: " << max_prob << std::endl; return classLabels[max_index]; } return "unknown"; } }; // ---------- 全局模型实例 ---------- TFLiteModel tflite_model; // ---------- 函数声明 ---------- void GetLineROI(Mat src, Mat &ROI); void GetSignROI(Mat src, Mat &ROI); bool detectBackgroundPresence(Mat &img); int detectABLetter(Mat &img); double PID(double error1); int atc(int angle); int dong(); int xunji(Mat frame); void preprocessImg(Mat img, Mat &gray, Mat &canny); void saveDebugImage(Mat img, string name, int frame_count); void performAction(int letter); // ---------- 保存调试图像 ---------- void saveDebugImage(Mat img, string name, int frame_count) { if (debug_save && frame_count % 10 == 0) { string filename = "/tmp/" + name + "_" + to_string(frame_count) + ".jpg"; imwrite(filename, img); cout << "Saved debug image: " << filename << endl; } } // ---------- 巡线ROI(图像下方) ---------- void GetLineROI(Mat src, Mat &ROI) { int width = src.cols; int height = src.rows; Rect rect(Point(width/6, height*2/3), Point(5*width/6, height)); ROI = src(rect).clone(); } // ---------- 标志检测ROI(图像上方) ---------- void GetSignROI(Mat src, Mat &ROI) { int width = src.cols; int height = src.rows; Rect rect(Point(width/4, height/4), Point(3*width/4, height/2)); ROI = src(rect).clone(); } // ---------- 图像预处理 ---------- void preprocessImg(Mat img, Mat &gray, Mat &canny) { cvtColor(img, gray, COLOR_BGR2GRAY); GaussianBlur(gray, gray, Size(5, 5), 0.5, 0.5); Canny(gray, canny, 30, 90, 3); } // ---------- 背景存在检测 ---------- bool detectBackgroundPresence(Mat &img) { Mat roi; GetSignROI(img, roi); if (roi.empty()) { return false; } // 使用多种颜色检测背景 Mat hsv; cvtColor(roi, hsv, COLOR_BGR2HSV); // 检测红色背景 Mat red_mask1, red_mask2; inRange(hsv, Scalar(0, 50, 50), Scalar(10, 255, 255), red_mask1); inRange(hsv, Scalar(170, 50, 50), Scalar(180, 255, 255), red_mask2); Mat red_mask = red_mask1 | red_mask2; // 检测蓝色背景 Mat blue_mask; inRange(hsv, Scalar(100, 50, 50), Scalar(130, 255, 255), blue_mask); int red_pixels = countNonZero(red_mask); int blue_pixels = countNonZero(blue_mask); double red_ratio = (double)red_pixels / (roi.rows * roi.cols); double blue_ratio = (double)blue_pixels / (roi.rows * roi.cols); cout << "Background detection - Red: " << red_ratio*100 << "%, Blue: " << blue_ratio*100 << "%"<< endl; return (red_ratio > 0.1 || blue_ratio > 0.1 ); } // ---------- A/B字母检测(使用训练模型) ---------- int detectABLetter(Mat &img) { Mat roi; GetSignROI(img, roi); if (roi.empty()) { cout << "Sign ROI is empty!" << endl; return 0; } saveDebugImage(roi, "sign_roi", 0); float confidence; string prediction = tflite_model.classify(roi, confidence); // 设置置信度阈值 const float confidence_threshold = 0.7f; if (confidence >= confidence_threshold) { if (prediction == "A") { cout << "*** Model detected A with confidence: " << confidence << " ***" << endl; // 在图像上标记检测结果 Rect global_rect( img.cols/4, img.rows/4, img.cols/2, img.rows/4 ); rectangle(img, global_rect, Scalar(0, 255, 0), 3); putText(img, "A (" + to_string(confidence).substr(0,4) + ")", Point(global_rect.x, global_rect.y-10), FONT_HERSHEY_SIMPLEX, 1, Scalar(0, 255, 0), 2); return 1; } else if (prediction == "B") { cout << "*** Model detected B with confidence: " << confidence << " ***" << endl; // 在图像上标记检测结果 Rect global_rect( img.cols/4, img.rows/4, img.cols/2, img.rows/4 ); rectangle(img, global_rect, Scalar(0, 255, 0), 3); putText(img, "B (" + to_string(confidence).substr(0,4) + ")", Point(global_rect.x, global_rect.y-10), FONT_HERSHEY_SIMPLEX, 1, Scalar(0, 255, 0), 2); return 2; } } else { cout << "Low confidence prediction: " << prediction << " (" << confidence << ")" << endl; } return 0; } // ---------- PID控制 ---------- double PID(double error) { double angle = kp * error + kd * (error - last_error); last_error = error; return angle; } // ---------- 舵机角度转占空比 ---------- int atc(int angle) { int pulse_width = 500 + (angle / 180.0) * 2000; int duty = pulse_width / 20000.0 * 100; return duty; } // ---------- 硬件初始化 ---------- int dong() { if (gpioInitialise() < 0) { cout << "pigpio init error" << endl; return -1; } gpioSetMode(pwm_pin, PI_OUTPUT); gpioSetPWMfrequency(pwm_pin, pwm_freq1); gpioSetPWMrange(pwm_pin, pwm_range1); gpioSetMode(servo_pin, PI_OUTPUT); gpioSetPWMfrequency(servo_pin, pwm_freq2); gpioSetPWMrange(servo_pin, pwm_range2); gpioPWM(pwm_pin, init_duty); gpioPWM(servo_pin, atc(82)); cout << "pigpio ok!" << endl; sleep(2); return 0; } // ---------- 巡线控制 ---------- int xunji(Mat frame) { Mat img, gray, canny; GetLineROI(frame, img); preprocessImg(img, gray, canny); int cols = canny.cols, rows = canny.rows; vector<int> mid(rows, -1); int mid_sum = 0, valid_cnt = 0; int start_row = min(rows - 50, rows - 1); int end_row = max(rows - 150, 0); for (int i = start_row; i >= end_row; i--) { bool left_lost = true, right_lost = true; int left_edge = -1, right_edge = -1; // 寻找左边缘 for (int j = cols / 2; j >= 20; j--) { if (canny.at<uchar>(i, j) == 255) { left_edge = j; left_lost = false; break; } } if (left_lost) { left_edge = 0; } // 寻找右边缘 for (int j = cols / 2; j < cols - 20; j++) { if (canny.at<uchar>(i, j) == 255) { right_edge = j; right_lost = false; break; } } if (right_lost) { right_edge = cols - 1; } if (!left_lost && !right_lost) { int center = (left_edge + right_edge) / 2; mid[valid_cnt] = center; mid_sum += center; valid_cnt++; } } if (valid_cnt > 0) { double center_avg = mid_sum / valid_cnt; double error = center_avg - cols / 2; double angle = PID(error); angle = 82 - angle; angle = max(min_ang, min(max_ang, angle)); cout << "Line following - Valid rows: " << valid_cnt << ", Error: " << error << ", Angle: " << angle << endl; gpioPWM(servo_pin, atc((int)angle)); return 1; } else { cout << "Line lost! No valid center points found." << endl; gpioPWM(servo_pin, atc(82)); return 0; } } // ---------- 执行动作函数 ---------- void performAction(int letter) { if (letter == 1) { cout << "=== Performing A Action: Turn Left ===" << endl; // 停止前进 gpioPWM(pwm_pin, 9300); usleep(200000); // 左转 gpioPWM(servo_pin, atc(75)); gpioPWM(pwm_pin, 9300); usleep(1000000); // 转回直行 gpioPWM(servo_pin, atc(82)); gpioPWM(pwm_pin, 9300); usleep(500000); } else if (letter == 2) { cout << "=== Performing B Action: Turn Right ===" << endl; // 停止前进 gpioPWM(pwm_pin, 9300); usleep(200000); // 右转 gpioPWM(servo_pin, atc(89)); gpioPWM(pwm_pin, 9300); usleep(1000000); // 转回直行 gpioPWM(servo_pin, atc(82)); gpioPWM(pwm_pin, 9300); usleep(500000); } } // ---------- 主函数 ---------- int main() { cout << "=== A/B Letter Detection with Trained Model ===" << endl; cout << "Using TensorFlow Lite for letter recognition" << endl; cout << "==============================================" << endl; // 加载训练模型 cout << "Loading TensorFlow Lite model..." << endl; if (!tflite_model.loadModel("car_model.tflite")) { cout << "Failed to load TFLite model!" << endl; return -1; } if (!tflite_model.loadLabels("class_indices.json")) { cout << "Failed to load labels!" << endl; return -1; } if (dong() < 0) { cout << "pigpio error !" << endl; return -1; } VideoCapture cap(0); if (!cap.isOpened()) { cout << "cap error" << endl; gpioPWM(pwm_pin, 0); gpioTerminate(); return -1; } // 设置摄像头参数 cap.set(CAP_PROP_FRAME_WIDTH, 640); cap.set(CAP_PROP_FRAME_HEIGHT, 480); cap.set(CAP_PROP_FPS, 30); Mat frame; int frame_count = 0; int detection_interval = 5; int line_lost_count = 0; const int max_line_lost = 30; int sign_detection_count = 0; const int sign_confirm_threshold = 2; cout << "Starting A/B letter detection with trained model..." << endl; cout << "A: Turn Left, B: Turn Right" << endl; // 初始前进 gpioPWM(pwm_pin, 9300); try { while (cap.read(frame)) { frame_count++; // 正常巡线 int line_status = xunji(frame); if (line_status == 0) { line_lost_count++; if (line_lost_count > max_line_lost) { cout << "Line lost for too long, stopping!" << endl; gpioPWM(pwm_pin, 6000); break; } } else { line_lost_count = 0; } // 检测标志和字母 if (frame_count % detection_interval == 0 && action_cooldown <= 0) { // 第一步:检测背景是否存在 bool background_present = detectBackgroundPresence(frame); if (background_present) { sign_detection_count++; cout << "Background detected: " << sign_detection_count << "/" << sign_confirm_threshold << endl; // 如果连续检测到背景,认为标志稳定 if (sign_detection_count >= sign_confirm_threshold && !ab_detected) { // 第二步:使用训练模型识别字母 int detected = detectABLetter(frame); if (detected != 0) { ab_detected = true; detected_letter = detected; cout << "=== LETTER DETECTED: " << (detected == 1 ? "A" : "B") << " ===" << endl; // 执行动作 performAction(detected); // 设置冷却时间 action_cooldown = 150; // 重置检测计数 sign_detection_count = 0; } } } else { // 没有检测到背景,重置计数器 sign_detection_count = 0; } } // 更新冷却时间 if (action_cooldown > 0) { action_cooldown--; } // 重置检测状态 if (action_cooldown == 0 && ab_detected) { ab_detected = false; detected_letter = 0; cout << "Reset detection state, ready for next sign" << endl; } usleep(10000); } } catch (const exception& e) { cout << "Exception occurred: " << e.what() << endl; } // 清理 gpioPWM(pwm_pin, 0); gpioPWM(servo_pin, atc(82)); gpioTerminate(); cap.release(); cout << "Program exited!" << endl; return 0; }cmake
最新发布
10-24
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值