// Copyright 2019 Google LLC // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // https://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. using System; using System.Collections.Generic; using UnityEngine; namespace Google.Play.AssetDelivery.Internal { /// /// Forwards pack state updates coming from play core. /// We can't receive updates while the app is in the background, so this MonoBehaviour ensures that pack states /// are updated when the app enters the foreground. /// internal class AssetDeliveryUpdateHandler : MonoBehaviour { public event Action OnStateUpdateEvent = delegate { }; /// /// The pack names of any AssetBundles that have received state updates after GetPackStates but before the /// Play Core Task has completed. This is to prevent the race condition between the task returned from /// and /// . /// private readonly HashSet _stateUpdatesSinceGetPackStates = new HashSet(); private bool _gettingPackStates; private AssetPackStateUpdateListener _stateUpdateListener; private AssetPackManager _assetPackManager; private PlayRequestRepository _requestRepository; public static AssetDeliveryUpdateHandler CreateInScene(AssetPackManager assetPackManager, PlayRequestRepository requestRepository) { var componentHolder = new GameObject(); DontDestroyOnLoad(componentHolder); componentHolder.name = "AssetDeliveryUpdateHandler"; var instance = componentHolder.AddComponent(); instance.Init(assetPackManager, requestRepository); return instance; } private void Init(AssetPackManager assetPackManager, PlayRequestRepository requestRepository) { _assetPackManager = assetPackManager; _requestRepository = requestRepository; _stateUpdateListener = new AssetPackStateUpdateListener(); _stateUpdateListener.OnStateUpdateEvent += OnStateUpdateReceived; StartListeningForUpdates(); } private void Start() { if (_assetPackManager == null || _stateUpdateListener == null) { throw new InvalidOperationException("AssetDeliveryUpdateHandler was never initialized."); } } private void OnApplicationPause(bool isPaused) { if (isPaused) { StopListeningForUpdates(); } else { StartListeningForUpdates(); ForcePackStatesUpdate(); } } private void OnDestroy() { StopListeningForUpdates(); } /// /// Asks for the current pack states and routes them to /// . /// private void ForcePackStatesUpdate() { if (_gettingPackStates) { Debug.LogWarning( "ForceStateUpdate attempt ignored because the latest states are still being retrieved."); return; } var activeRequestBundleNames = _requestRepository.GetActiveAssetPackNames(); if (activeRequestBundleNames.Length == 0) { // No requests to update. return; } BeginGetPackStates(); var getPackStateTask = _assetPackManager.GetPackStates(activeRequestBundleNames); getPackStateTask.RegisterOnSuccessCallback(ProcessPackStates); } /// /// Processes a java AssetPackStates object and invokes for each pack /// state it contains. /// /// A java object representing a AssetPackStates object. private void ProcessPackStates(AndroidJavaObject javaPackStates) { try { var packStates = new AssetPackStates(javaPackStates); foreach (var packStatePair in packStates.PackStates) { if (_stateUpdatesSinceGetPackStates.Contains(packStatePair.Key)) { // A newer state update was received before the getPackStateTask finished. // Discard this state. continue; } OnStateUpdateEvent.Invoke(packStatePair.Value); } } finally { EndGetPackStates(); } } private void OnStateUpdateReceived(AssetPackState newState) { if (_gettingPackStates) { _stateUpdatesSinceGetPackStates.Add(newState.Name); } OnStateUpdateEvent.Invoke(newState); } private void BeginGetPackStates() { _gettingPackStates = true; } private void EndGetPackStates() { _gettingPackStates = false; _stateUpdatesSinceGetPackStates.Clear(); } private void StartListeningForUpdates() { _assetPackManager.RegisterListener(_stateUpdateListener); } private void StopListeningForUpdates() { _assetPackManager.UnregisterListener(_stateUpdateListener); } } }