// 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);
}
}
}