chunk 2: remaining non-audio non-NewImport assets

This commit is contained in:
2026-04-06 11:25:19 +03:00
parent 0d11a097d8
commit ed675b9f4a
3742 changed files with 1640416 additions and 0 deletions

View File

@@ -0,0 +1,30 @@
// 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 Google.Play.Common.Internal;
namespace Google.Play.AssetDelivery.Internal
{
/// <summary>
/// Represents an asynchronous operation that produces a result or an AssetDeliveryErrorCode upon completion.
/// </summary>
/// <typeparam name="TResult">The type of the result of the operation.</typeparam>
internal class AssetDeliveryAsyncOperation<TResult> : PlayAsyncOperationImpl<TResult, AssetDeliveryErrorCode>
{
public override bool IsSuccessful
{
get { return IsDone && Error == AssetDeliveryErrorCode.NoError; }
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 567126ac059a42489a8e5a8a7639dd1c
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,176 @@
// 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
{
/// <summary>
/// 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.
/// </summary>
internal class AssetDeliveryUpdateHandler : MonoBehaviour
{
public event Action<AssetPackState> OnStateUpdateEvent = delegate { };
/// <summary>
/// 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
/// <see cref="AssetPackManager.GetPackStates"/> and
/// <see cref="AssetPackStateUpdateListener.OnStateUpdateEvent"/>.
/// </summary>
private readonly HashSet<string> _stateUpdatesSinceGetPackStates = new HashSet<string>();
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<AssetDeliveryUpdateHandler>();
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();
}
/// <summary>
/// Asks <see cref="AssetPackManager"/> for the current pack states and routes them to
/// <see cref="OnForcedStateUpdate"/>.
/// </summary>
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);
}
/// <summary>
/// Processes a java AssetPackStates object and invokes <see cref="OnForcedStateUpdate"/> for each pack
/// state it contains.
/// </summary>
/// <param name="javaPackStates">A java object representing a AssetPackStates object.</param>
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);
}
}
}

View File

@@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: bb8fa3dd35e1c4dc790b1faa33b0265c
timeCreated: 1554494584
licenseType: Pro
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,50 @@
// Copyright 2020 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.Text;
using UnityEngine;
namespace Google.Play.AssetDelivery.Internal
{
/// <summary>
/// Provides an internal implementation for AssetLocation.
/// </summary>
public class AssetLocationImpl : AssetLocation
{
/// <summary>
/// Creates an AssetPackLocation with all the fields of the underlying Java object, disposing the Java
/// object in the process.
/// </summary>
public AssetLocationImpl(AndroidJavaObject packLocation)
{
using (packLocation)
{
Path = packLocation.Call<string>("path");
// Cast to uint because Unity AssetBundle loading APIs expect uint offset.
Offset = (ulong) packLocation.Call<long>("offset");
Size = (ulong) packLocation.Call<long>("size");
}
}
public override string ToString()
{
var stateDescription = new StringBuilder();
stateDescription.AppendFormat("path: {0}\n", Path);
stateDescription.AppendFormat("offset: {0}\n", Offset);
stateDescription.AppendFormat("size: {0}\n", Size);
return stateDescription.ToString();
}
}
}

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 006516d0561e414dbe8a46b07c73c4cc
timeCreated: 1588294051

View File

@@ -0,0 +1,60 @@
// 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.Text;
using Google.Play.Core.Internal;
using UnityEngine;
namespace Google.Play.AssetDelivery.Internal
{
/// <summary>
/// Wraps Play Core's AssetPackLocation which represents the location of an asset pack on disk.
/// </summary>
internal class AssetPackLocation
{
/// <summary>
/// The path to the directory which will contain the contents of an asset pack, if the asset pack is available
/// on disk.
/// </summary>
public string Path { get; private set; }
/// <summary>
/// Returns whether the pack is installed as an APK or unpackaged into a folder on the filesystem.
/// </summary>
public AssetPackStorageMethod PackStorageMethod { get; private set; }
/// <summary>
/// Creates an AssetPackLocation with all the fields of the underlying Java object, disposing the Java
/// object in the process.
/// </summary>
public AssetPackLocation(AndroidJavaObject packLocation)
{
using (packLocation)
{
// Called with AndroidJavaObject instead of string because path may be null.
var javaPathString = packLocation.Call<AndroidJavaObject>("path");
Path = PlayCoreHelper.ConvertJavaString(javaPathString);
PackStorageMethod = (AssetPackStorageMethod) packLocation.Call<int>("packStorageMethod");
}
}
public override string ToString()
{
var stateDescription = new StringBuilder();
stateDescription.AppendFormat("path: {0}\n", Path);
stateDescription.AppendFormat("packStorageMethod: {0}\n", PackStorageMethod);
return stateDescription.ToString();
}
}
}

View File

@@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: 5c3389864c64846d9ae474033eba316f
timeCreated: 1554317027
licenseType: Pro
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,223 @@
// 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 Google.Play.Common;
using Google.Play.Core.Internal;
using UnityEngine;
namespace Google.Play.AssetDelivery.Internal
{
/// <summary>
/// Wraps Play Core's AssetPackManager which manages downloads of asset packs.
/// </summary>
internal class AssetPackManager : IDisposable
{
private AndroidJavaObject _javaAssetPackManager;
public AssetPackManager()
{
const string factoryClassName = PlayCoreConstants.AssetPackPackagePrefix + "AssetPackManagerFactory";
using (var activity = UnityPlayerHelper.GetCurrentActivity())
using (var assetPackManagerFactory = new AndroidJavaClass(factoryClassName))
{
_javaAssetPackManager = assetPackManagerFactory.CallStatic<AndroidJavaObject>("getInstance", activity);
}
if (_javaAssetPackManager == null)
{
throw new NullReferenceException("Play Core returned null AssetPackManager");
}
}
/// <summary>
/// Registers a listener that will be called when a pack download changes state.
/// Listeners should be subsequently unregistered using <see cref="UnregisterListener"/>
/// </summary>
/// <param name="listener">
/// An AndroidJavaProxy representing a java object of class:
/// com.google.android.play.core.assetpacks.AssetPackStateUpdateListener
/// </param>
public void RegisterListener(AndroidJavaProxy listener)
{
_javaAssetPackManager.Call("registerListener", listener);
}
/// <summary>
/// Calls Play Core to unregister a listener previously added using <see cref="RegisterListener"/>
/// </summary>
/// <param name="listener">
/// An AndroidJavaProxy representing a java object of class:
/// com.google.android.play.core.assetpacks.AssetPackStateUpdateListener
/// </param>
public void UnregisterListener(AndroidJavaProxy listener)
{
_javaAssetPackManager.Call("unregisterListener", listener);
}
/// <summary>
/// Calls Play Core to start a download for the specified asset packs.
/// </summary>
/// <param name="assetPackNames">The asset packs to include in the download request.</param>
/// <returns>
/// A wrapped Play Core task, which will return a AndroidJavaObject representing an
/// AssetPackStates. The caller is responsible for disposing this task.
/// </returns>
public PlayServicesTask<AndroidJavaObject> Fetch(params string[] assetPackNames)
{
using (var request = BuildAssetPackList(assetPackNames))
{
var javaTask = _javaAssetPackManager.Call<AndroidJavaObject>("fetch", request);
return new PlayServicesTask<AndroidJavaObject>(javaTask);
}
}
/// <summary>
/// Calls Play Core to get the states of the specified packs.
/// </summary>
/// <returns>
/// A wrapped Play Core task, which will return a AndroidJavaObject representing an
/// AssetPackStates. The caller is responsible for disposing this task.
/// </returns>
public PlayServicesTask<AndroidJavaObject> GetPackStates(params string[] assetPackNames)
{
using (var packList = BuildAssetPackList(assetPackNames))
{
var javaTask = _javaAssetPackManager.Call<AndroidJavaObject>("getPackStates", packList);
return new PlayServicesTask<AndroidJavaObject>(javaTask);
}
}
/// <summary>
/// Calls Play Core to get the location of the specified asset pack.
/// This should contain the AssetBundle associated with the specified asset pack.
/// </summary>
/// <returns>
/// The AssetPackLocation containing the contents of the specified asset pack, or null if the most up-to-date
/// version of this asset pack isn't available on disk.
/// </returns>
public AssetPackLocation GetPackLocation(string assetPackName)
{
var javaPackLocation = _javaAssetPackManager.Call<AndroidJavaObject>("getPackLocation", assetPackName);
return PlayCoreHelper.IsNull(javaPackLocation) ? null : new AssetPackLocation(javaPackLocation);
}
/// <summary>
/// Calls Play Core to get the location of the specified asset within the specified asset pack.
/// </summary>
/// <returns>
/// The AssetLocation of the specified asset or null if the most up-to-date
/// version of this asset pack isn't available on disk.
/// </returns>
public AssetLocation GetAssetLocation(string assetPackName, string assetPath)
{
var javaAssetLocation =
_javaAssetPackManager.Call<AndroidJavaObject>("getAssetLocation", assetPackName, assetPath);
return PlayCoreHelper.IsNull(javaAssetLocation) ? null : new AssetLocationImpl(javaAssetLocation);
}
/// <summary>
/// Requests to cancel the download for a list of packs.
/// </summary>
/// <returns>
/// Returns a AndroidJavaObject representing an AssetPackStates which contains the new states
/// of all specified assetPackNames.
/// </returns>
public AndroidJavaObject Cancel(params string[] assetPackNames)
{
using (var packList = BuildAssetPackList(assetPackNames))
{
var javaPackStates = _javaAssetPackManager.Call<AndroidJavaObject>("cancel", packList);
return javaPackStates;
}
}
/// <summary>
/// Deletes the specified asset pack from internal storage of the app.
/// Deleted packs will not be re-downloaded after update.
/// If the asset pack is currently being downloaded or installed, this method will not cancel the process.
/// </summary>
/// <returns>
/// A PlayServicesTask representing a Task{Void} that will only be successful if files were successfully
/// deleted.
/// </returns>
public PlayServicesTask<AndroidJavaObject> RemovePack(string assetPackName)
{
var javaTask = _javaAssetPackManager.Call<AndroidJavaObject>("removePack", assetPackName);
return new PlayServicesTask<AndroidJavaObject>(javaTask);
}
/// <summary>
/// Calls Play Core to show a confirmation dialog for all downloads that are currently in the
/// <see cref="AssetDeliveryStatus.WaitingForWifi"/> state. If the user accepts the dialog, then those
/// packs are downloaded over cellular data.
/// </summary>
/// <returns>
/// Returns a <see cref=" PlayServicesTask{ActivityResult}"/> that completes once the dialog has been accepted,
/// denied or closed. A successful task result contains one of the following values:
/// <ul>
/// <li><see cref="ActivityResult.ResultOk"/> if the user accepted.</li>
/// <li><see cref="ActivityResult.ResultCancelled"/> if the user denied or the dialog has been closed in
/// any other way (e.g. backpress).</li>
/// </ul>
/// </returns>
public PlayServicesTask<int> ShowCellularDataConfirmation()
{
var task = _javaAssetPackManager.Call<AndroidJavaObject>("showCellularDataConfirmation",
UnityPlayerHelper.GetCurrentActivity());
return new PlayServicesTask<int>(task);
}
/// <summary>
/// Calls the Java Asset Delivery SDK to show a confirmation dialog for all downloads that
/// are currently in either the <see cref="AssetDeliveryStatus.RequiresUserConfirmation"/>
/// state or the <see cref="AssetDeliveryStatus.WaitingForWifi"/> state.
/// </summary>
/// <returns>
/// Returns a <see cref=" PlayServicesTask{ActivityResult}"/> that completes once the dialog
/// has been accepted, denied or closed. A successful task result contains one of the
/// following values:
/// <ul>
/// <li><see cref="ActivityResult.ResultOk"/> if the user accepted.</li>
/// <li><see cref="ActivityResult.ResultCancelled"/> if the user denied or the dialog has
/// been closed in
/// any other way (e.g. backpress).</li>
/// </ul>
/// </returns>
public PlayServicesTask<int> ShowConfirmationDialog()
{
var task = _javaAssetPackManager.Call<AndroidJavaObject>("showConfirmationDialog",
UnityPlayerHelper.GetCurrentActivity());
return new PlayServicesTask<int>(task);
}
// Returns a list of asset pack names.
private static AndroidJavaObject BuildAssetPackList(params string[] assetPackNames)
{
var assetPackList = new AndroidJavaObject("java.util.ArrayList");
foreach (var packName in assetPackNames)
{
assetPackList.Call<bool>("add", packName);
}
return assetPackList;
}
public void Dispose()
{
_javaAssetPackManager.Dispose();
}
}
}

View File

@@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: 04178671ed4954e2bb56c84dd03d92bc
timeCreated: 1549564032
licenseType: Pro
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,78 @@
// 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.Text;
using UnityEngine;
namespace Google.Play.AssetDelivery.Internal
{
/// <summary>
/// Wraps Play Core's AssetPackState which represents the current state of an AssetPack download.
/// </summary>
internal class AssetPackState
{
/// <summary>
/// The name of the asset pack being downloaded.
/// </summary>
public string Name { get; private set; }
/// <summary>
/// The number of bytes downloaded so far.
/// </summary>
public long BytesDownloaded { get; private set; }
/// <summary>
/// The total number of bytes that need to be downloaded.
/// </summary>
public long TotalBytesToDownload { get; private set; }
/// <summary>
/// The status of the associated download session (downloading, downloaded, installed, etc).
/// </summary>
public int Status { get; private set; }
/// <summary>
/// The error code indicating the reason the download session failed.
/// </summary>
public int ErrorCode { get; private set; }
/// <summary>
/// Creates an AssetPackState with all the fields of the underlying Java object, disposing the Java
/// object in the process.
/// </summary>
public AssetPackState(AndroidJavaObject javaAssetPackState)
{
using (javaAssetPackState)
{
Name = javaAssetPackState.Call<string>("name");
BytesDownloaded = javaAssetPackState.Call<long>("bytesDownloaded");
TotalBytesToDownload = javaAssetPackState.Call<long>("totalBytesToDownload");
Status = javaAssetPackState.Call<int>("status");
ErrorCode = javaAssetPackState.Call<int>("errorCode");
}
}
public override string ToString()
{
var stateDescription = new StringBuilder();
stateDescription.AppendFormat("name: {0}\n", Name);
stateDescription.AppendFormat("status: {0}\n", Status);
stateDescription.AppendFormat("error code: {0}\n", ErrorCode);
stateDescription.AppendFormat("bytes downloaded: {0}\n", BytesDownloaded);
stateDescription.AppendFormat("total downloaded: {0}\n", TotalBytesToDownload);
return stateDescription.ToString();
}
}
}

View File

@@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: b9528fb96e4de4c618a777a82382ba6e
timeCreated: 1551829374
licenseType: Pro
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,41 @@
// 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 Google.Play.Core.Internal;
using UnityEngine;
namespace Google.Play.AssetDelivery.Internal
{
/// <summary>
/// Proxy for Play Core's AssetPackStateUpdateListener class.
/// Used to receive callbacks from Play Core's AssetPackManager.
/// </summary>
internal class AssetPackStateUpdateListener : AndroidJavaProxy
{
public event Action<AssetPackState> OnStateUpdateEvent = delegate { };
public AssetPackStateUpdateListener() :
base(PlayCoreConstants.AssetPackPackagePrefix + "AssetPackStateUpdateListener")
{
}
// Proxied java calls. Method names are camelCase to match the corresponding java methods.
public void onStateUpdate(AndroidJavaObject assetPacksState)
{
var packState = new AssetPackState(assetPacksState);
PlayCoreEventHandler.HandleEvent(() => OnStateUpdateEvent.Invoke(packState));
}
}
}

View File

@@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: d0dc15ad4480243fb8c18279cbae4fa6
timeCreated: 1549327262
licenseType: Pro
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,69 @@
// 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.Collections.Generic;
using System.Linq;
using System.Text;
using Google.Play.Core.Internal;
using UnityEngine;
namespace Google.Play.AssetDelivery.Internal
{
/// <summary>
/// Wraps Play Core's AssetPackStates which represents the current state of all requested asset packs.
/// </summary>
internal class AssetPackStates
{
/// <summary>
/// The total size of all requested packs in bytes.
/// </summary>
public long TotalBytes { get; private set; }
/// <summary>
/// A dictionary containing the download states of all requested asset packs.
/// </summary>
public Dictionary<string, AssetPackState> PackStates { get; private set; }
/// <summary>
/// Creates an AssetPackStates with all the fields of the underlying Java object.
/// </summary>
public AssetPackStates(AndroidJavaObject packStates)
{
using (packStates)
{
TotalBytes = packStates.Call<long>("totalBytes");
PackStates = ConvertPackStatesJavaMapToDictionary(packStates);
}
}
private Dictionary<string, AssetPackState> ConvertPackStatesJavaMapToDictionary(
AndroidJavaObject packStates)
{
using (var javaMap = packStates.Call<AndroidJavaObject>("packStates"))
{
return PlayCoreHelper.ConvertJavaMap<string, AndroidJavaObject>(javaMap)
.ToDictionary(kvp => kvp.Key, kvp => new AssetPackState(kvp.Value));
}
}
public override string ToString()
{
var stateDescription = new StringBuilder();
stateDescription.AppendFormat("total bytes: {0}\n", TotalBytes);
stateDescription.AppendLine("pack names: " + string.Join(", ", PackStates.Keys.ToArray()));
return stateDescription.ToString();
}
}
}

View File

@@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: b31a4c75852ef49b18cecbbae7c55449
timeCreated: 1549325414
licenseType: Pro
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,34 @@
// 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.
namespace Google.Play.AssetDelivery.Internal
{
/// <summary>
/// Wraps Play Core's AssetPackLocation which represents the location of an asset pack on disk.
/// </summary>
internal enum AssetPackStorageMethod
{
/// <summary>
/// Indicates that the asset pack is unpackaged into a folder containing individual asset files.
/// Assets contained by this asset pack can be accessed via standard File APIs.
/// </summary>
StorageFiles = 0,
/// <summary>
/// Indicates that the asset pack is installed as APKs containing asset files.
/// Assets contained by this asset pack can be accessed via Asset Manager.
/// </summary>
ApkAssets = 1,
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: bba029dc886c42318f5344e02844a7ea
timeCreated: 1562870321
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,138 @@
// 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;
using UnityEngine;
namespace Google.Play.AssetDelivery.Internal
{
internal class PlayAssetBundleRequestImpl : PlayAssetBundleRequest
{
internal readonly PlayAssetPackRequestImpl PackRequest;
private readonly AssetDeliveryUpdateHandler _updateHandler;
private AssetDeliveryStatus _loadingStatus;
private AssetDeliveryErrorCode _loadingError;
public PlayAssetBundleRequestImpl(PlayAssetPackRequestImpl packRequest,
AssetDeliveryUpdateHandler updateHandler)
{
PackRequest = packRequest;
_updateHandler = updateHandler;
_loadingStatus = AssetDeliveryStatus.Pending;
_loadingError = AssetDeliveryErrorCode.NoError;
PackRequest.Completed += OnPackRequestCompleted;
}
public override event Action<PlayAssetBundleRequest> Completed
{
add
{
if (IsDone)
{
value.Invoke(this);
return;
}
base.Completed += value;
}
remove { base.Completed -= value; }
}
public override float DownloadProgress
{
get { return PackRequest.DownloadProgress; }
}
public override AssetDeliveryStatus Status
{
get { return PackRequest.Status == AssetDeliveryStatus.Available ? _loadingStatus : PackRequest.Status; }
}
public override AssetDeliveryErrorCode Error
{
get { return PackRequest.Error == AssetDeliveryErrorCode.NoError ? _loadingError : PackRequest.Error; }
}
private void OnLoadingErrorOccurred(AssetDeliveryErrorCode errorCode)
{
if (IsDone)
{
return;
}
IsDone = true;
_loadingError = errorCode;
_loadingStatus = AssetDeliveryStatus.Failed;
AssetBundle = null;
InvokeCompletedEvent();
}
private void OnLoadingFinished(AssetBundle loadedAssetBundle)
{
if (IsDone)
{
return;
}
DownloadProgress = 1f;
AssetBundle = loadedAssetBundle;
_loadingStatus = AssetDeliveryStatus.Loaded;
IsDone = true;
InvokeCompletedEvent();
}
private void OnPackRequestCompleted(PlayAssetPackRequest packRequest)
{
packRequest.Completed -= OnPackRequestCompleted;
if (packRequest.Error == AssetDeliveryErrorCode.NoError)
{
StartLoadingAssetBundle();
}
else
{
IsDone = true;
InvokeCompletedEvent();
}
}
private void StartLoadingAssetBundle()
{
_updateHandler.StartCoroutine(CoLoadAssetBundle());
DownloadProgress = 1f;
_loadingStatus = AssetDeliveryStatus.Loading;
}
private IEnumerator CoLoadAssetBundle()
{
// Assume that the AssetBundle name equals the asset pack name.
var bundleCreateRequest = PackRequest.LoadAssetBundleAsync(PackRequest.AssetPackName);
yield return bundleCreateRequest;
if (bundleCreateRequest.assetBundle == null)
{
OnLoadingErrorOccurred(AssetDeliveryErrorCode.AssetBundleLoadingError);
yield break;
}
OnLoadingFinished(bundleCreateRequest.assetBundle);
}
public override void AttemptCancel()
{
PackRequest.AttemptCancel();
}
}
}

View File

@@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: 2fd44a50730bf4888ac9dfa4416e0a87
timeCreated: 1550014332
licenseType: Pro
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,464 @@
// Copyright 2020 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 System.IO;
using System.Linq;
using Google.Play.Common;
using Google.Play.Core.Internal;
using UnityEngine;
namespace Google.Play.AssetDelivery.Internal
{
/// <summary>
/// Internal implementation of <see cref="PlayAssetDelivery"/> methods.
/// </summary>
internal class PlayAssetDeliveryInternal
{
/// <summary>
/// The subfolder, inside the "assets" directory, into which an asset pack file is stored.
/// This intermediate folder can be useful for targeting (by texture compression format) at build time.
/// </summary>
private const string AssetPackFolderName = "assetpack";
private readonly AssetPackManager _assetPackManager;
private readonly AssetDeliveryUpdateHandler _updateHandler;
private readonly PlayRequestRepository _requestRepository = new PlayRequestRepository();
internal PlayAssetDeliveryInternal()
{
_assetPackManager = new AssetPackManager();
_updateHandler = AssetDeliveryUpdateHandler.CreateInScene(_assetPackManager, _requestRepository);
_updateHandler.OnStateUpdateEvent += ProcessPackStateUpdate;
PlayCoreEventHandler.CreateInScene();
}
internal bool IsDownloaded(string assetBundleName)
{
return _assetPackManager.GetPackLocation(assetBundleName) != null;
}
internal PlayAssetBundleRequest RetrieveAssetBundleAsyncInternal(string assetBundleName)
{
var request = InitializeAssetBundleRequest(assetBundleName);
InitiateRequest(request.PackRequest);
return request;
}
internal PlayAssetBundleRequest RetrieveAssetBundleAsyncInternal(string assetBundleName, bool updateIfAvailable)
{
var request = InitializeAssetBundleRequest(assetBundleName);
InitiateRequest(request.PackRequest, updateIfAvailable);
return request;
}
private PlayAssetBundleRequestImpl InitializeAssetBundleRequest(string assetBundleName)
{
if (_requestRepository.ContainsRequest(assetBundleName))
{
throw new ArgumentException(string.Format("There is already an active request for AssetBundle: {0}",
assetBundleName));
}
var request = CreateAssetBundleRequest(assetBundleName);
_requestRepository.AddAssetBundleRequest(request);
request.Completed += req => _requestRepository.RemoveRequest(assetBundleName);
return request;
}
internal PlayAssetPackRequest RetrieveAssetPackAsyncInternal(string assetPackName)
{
var request = GetExistingAssetPackRequest(assetPackName);
if (request != null)
{
return request;
}
request = InitializeAssetPackRequest(assetPackName);
InitiateRequest(request);
return request;
}
internal PlayAssetPackRequest RetrieveAssetPackAsyncInternal(string assetPackName, bool updateIfAvailable)
{
var request = GetExistingAssetPackRequest(assetPackName);
if (request != null)
{
return request;
}
request = InitializeAssetPackRequest(assetPackName);
InitiateRequest(request, updateIfAvailable);
return request;
}
internal PlayAssetPackBatchRequest RetrieveAssetPackBatchAsyncInternal(IList<string> assetPackNames)
{
return CreateAndInitiateBatchRequest(assetPackNames, IsDownloaded);
}
internal PlayAssetPackBatchRequest RetrieveAssetPackBatchAsyncInternal(IList<string> assetPackNames,
bool updateIfAvailable)
{
Func<string, bool> useAvailablePack = packName => IsCurrentVersionGoodEnough(packName, updateIfAvailable);
return CreateAndInitiateBatchRequest(assetPackNames, useAvailablePack);
}
private PlayAssetPackBatchRequest CreateAndInitiateBatchRequest(IList<string> assetPackNames,
Func<string, bool> isPackAvailable)
{
if (assetPackNames.Count != assetPackNames.Distinct().Count())
{
throw new ArgumentException("assetPackNames contains duplicate entries");
}
var activeAssetBundleRequestNames = assetPackNames
.Where(name => _requestRepository.ContainsAssetBundleRequest(name))
.ToArray();
if (activeAssetBundleRequestNames.Length != 0)
{
throw new ArgumentException("Cannot create a new PlayAssetPackBatchRequests because there are " +
"already PlayAssetBundleRequests for AssetBundles: {0}",
string.Join(", ", activeAssetBundleRequestNames));
}
// A subset of assetPackNames of packs that are not available on disk.
var unavailableAssetPackNames = new List<string>();
var requests = new List<PlayAssetPackRequestImpl>();
foreach (var assetPackName in assetPackNames)
{
PlayAssetPackRequestImpl request;
if (_requestRepository.TryGetRequest(assetPackName, out request))
{
requests.Add(request);
continue;
}
request = CreateAssetPackRequest(assetPackName);
_requestRepository.AddRequest(request);
request.Completed += req => _requestRepository.RemoveRequest(request.AssetPackName);
requests.Add(request);
if (isPackAvailable.Invoke(assetPackName))
{
request.OnPackAvailable();
}
else
{
unavailableAssetPackNames.Add(assetPackName);
}
}
var batchRequest = new PlayAssetPackBatchRequestImpl(requests);
var fetchTask = _assetPackManager.Fetch(unavailableAssetPackNames.ToArray());
fetchTask.RegisterOnSuccessCallback(javaPackStates =>
{
batchRequest.OnInitializedInPlayCore();
fetchTask.Dispose();
});
fetchTask.RegisterOnFailureCallback((reason, errorCode) =>
{
Debug.LogError("Failed to retrieve asset pack batch: " + reason);
batchRequest.OnInitializationErrorOccurred(PlayCoreTranslator.TranslatePlayCoreErrorCode(errorCode));
fetchTask.Dispose();
});
return batchRequest;
}
internal PlayAsyncOperation<ConfirmationDialogResult, AssetDeliveryErrorCode>
ShowCellularDataConfirmationInternal()
{
var requests = _requestRepository.GetRequestsWithStatus(AssetDeliveryStatus.WaitingForWifi);
if (requests.Count == 0)
{
throw new Exception("There are no active requests waiting for wifi.");
}
var task = _assetPackManager.ShowCellularDataConfirmation();
var operation = new AssetDeliveryAsyncOperation<ConfirmationDialogResult>();
task.RegisterOnSuccessCallback(resultCode =>
{
operation.SetResult(ConvertToConfirmationDialogResult(resultCode));
task.Dispose();
});
task.RegisterOnFailureCallback((message, errorCode) =>
{
operation.SetError(PlayCoreTranslator.TranslatePlayCoreErrorCode(errorCode));
task.Dispose();
});
return operation;
}
internal PlayAsyncOperation<ConfirmationDialogResult, AssetDeliveryErrorCode>
ShowConfirmationDialogInternal()
{
var requestsAwaitingWifi = _requestRepository.GetRequestsWithStatus(AssetDeliveryStatus.WaitingForWifi);
var requestsAwaitingConsent = _requestRepository.GetRequestsWithStatus(AssetDeliveryStatus.RequiresUserConfirmation);
if (requestsAwaitingWifi.Count == 0 && requestsAwaitingConsent.Count == 0)
{
throw new Exception("There are no active requests waiting for confirmation.");
}
var task = _assetPackManager.ShowConfirmationDialog();
var operation = new AssetDeliveryAsyncOperation<ConfirmationDialogResult>();
task.RegisterOnSuccessCallback(resultCode =>
{
operation.SetResult(ConvertToConfirmationDialogResult(resultCode));
task.Dispose();
});
task.RegisterOnFailureCallback((message, errorCode) =>
{
operation.SetError(PlayCoreTranslator.TranslatePlayCoreErrorCode(errorCode));
task.Dispose();
});
return operation;
}
internal PlayAsyncOperation<long, AssetDeliveryErrorCode> GetDownloadSizeInternal(string assetBundleName)
{
var operation = new AssetDeliveryAsyncOperation<long>();
if (IsInstallTimeAssetBundle(assetBundleName))
{
operation.SetResult(0L);
return operation;
}
var task = _assetPackManager.GetPackStates(assetBundleName);
task.RegisterOnSuccessCallback(javaPackState =>
{
var assetPacks = new AssetPackStates(javaPackState);
operation.SetResult(assetPacks.TotalBytes);
task.Dispose();
});
task.RegisterOnFailureCallback((message, errorCode) =>
{
operation.SetError(PlayCoreTranslator.TranslatePlayCoreErrorCode(errorCode));
task.Dispose();
});
return operation;
}
internal PlayAsyncOperation<IDictionary<string, PlayAssetPackDownloadInfo>, AssetDeliveryErrorCode>
GetDownloadInfoInternal(IList<string> assetPackNames)
{
var operation = new AssetDeliveryAsyncOperation<IDictionary<string, PlayAssetPackDownloadInfo>>();
var task = _assetPackManager.GetPackStates(assetPackNames.ToArray());
task.RegisterOnSuccessCallback(javaPackStates =>
{
operation.SetResult(PlayAssetPackDownloadInfoImpl.FromAssetPackStates(javaPackStates));
task.Dispose();
});
task.RegisterOnFailureCallback((message, errorCode) =>
{
operation.SetError(PlayCoreTranslator.TranslatePlayCoreErrorCode(errorCode));
task.Dispose();
});
return operation;
}
internal PlayAsyncOperation<VoidResult, AssetDeliveryErrorCode> RemoveAssetPackInternal(
string assetBundleName)
{
var operation = new AssetDeliveryAsyncOperation<VoidResult>();
var task = _assetPackManager.RemovePack(assetBundleName);
task.RegisterOnSuccessCallback(javaPackState =>
{
operation.SetResult(new VoidResult());
task.Dispose();
});
task.RegisterOnFailureCallback((message, errorCode) =>
{
operation.SetError(AssetDeliveryErrorCode.InternalError);
task.Dispose();
});
return operation;
}
private AssetLocation GetAssetLocation(string assetBundleName)
{
var assetPath = Path.Combine(AssetPackFolderName, assetBundleName);
return _assetPackManager.GetAssetLocation(assetBundleName, assetPath);
}
private PlayAssetPackRequestImpl GetExistingAssetPackRequest(string assetPackName)
{
if (_requestRepository.ContainsAssetBundleRequest(assetPackName))
{
throw new ArgumentException(string.Format(
"Cannot create a new PlayAssetPackRequest because there is already an active " +
"PlayAssetBundleRequest for asset bundle: {0}",
assetPackName));
}
PlayAssetPackRequestImpl request;
if (_requestRepository.TryGetRequest(assetPackName, out request))
{
Debug.Log("Returning existing active request for " + assetPackName);
}
return request;
}
private PlayAssetPackRequestImpl InitializeAssetPackRequest(string assetPackName)
{
var request = CreateAssetPackRequest(assetPackName);
_requestRepository.AddRequest(request);
request.Completed += req => _requestRepository.RemoveRequest(assetPackName);
return request;
}
private PlayAssetPackRequestImpl CreateAssetPackRequest(string assetPackName)
{
return new PlayAssetPackRequestImpl(assetPackName, _assetPackManager, _requestRepository);
}
private PlayAssetBundleRequestImpl CreateAssetBundleRequest(string assetBundleName)
{
var packRequest = CreateAssetPackRequest(assetBundleName);
return new PlayAssetBundleRequestImpl(packRequest, _updateHandler);
}
private void InitiateRequest(PlayAssetPackRequestImpl request)
{
StartRequest(request, IsDownloaded(request.AssetPackName));
}
private void InitiateRequest(PlayAssetPackRequestImpl request, bool updateIfAvailable)
{
StartRequest(request, IsCurrentVersionGoodEnough(request.AssetPackName, updateIfAvailable));
}
private bool IsCurrentVersionGoodEnough(string assetPackName, bool wantNewerVersion)
{
var packLocation = _assetPackManager.GetPackLocation(assetPackName);
bool isCurrentVersionGoodEnough;
if (packLocation == null)
{
isCurrentVersionGoodEnough= false;
}
else if (packLocation.PackStorageMethod == AssetPackStorageMethod.ApkAssets)
{
// If the pack exists as an APK, then it is an install-time pack which cannot be updated.
isCurrentVersionGoodEnough = true;
}
else
{
// When wantNewerVersion is true,
// we can't use the version on disk without checking if a newer version exists.
isCurrentVersionGoodEnough = !wantNewerVersion;
}
return isCurrentVersionGoodEnough;
}
private void StartRequest(PlayAssetPackRequestImpl request, bool isAvailable)
{
if (isAvailable)
{
request.OnPackAvailable();
}
else
{
var fetchTask = _assetPackManager.Fetch(request.AssetPackName);
fetchTask.RegisterOnSuccessCallback(javaPackStates =>
{
request.OnInitializedInPlayCore();
fetchTask.Dispose();
});
fetchTask.RegisterOnFailureCallback((reason, errorCode) =>
{
Debug.LogErrorFormat("Failed to retrieve asset pack: {0}", reason);
request.OnErrorOccured(PlayCoreTranslator.TranslatePlayCoreErrorCode(errorCode));
fetchTask.Dispose();
});
}
}
private void ProcessPackStateUpdate(AssetPackState newState)
{
PlayAssetPackRequestImpl request;
if (!_requestRepository.TryGetRequest(newState.Name, out request))
{
Debug.LogWarningFormat(
"Received state update \"{0}\", that is not associated with an active request.",
newState.Name);
return;
}
UpdateRequest(request, newState, newState.ErrorCode);
}
private void UpdateRequest(PlayAssetPackRequestImpl request, AssetPackState newState, int errorCode)
{
if (request.IsDone)
{
// Ignore pack state updates associated with completed requests.
return;
}
var assetDeliveryErrorCode = PlayCoreTranslator.TranslatePlayCoreErrorCode(errorCode);
if (assetDeliveryErrorCode != AssetDeliveryErrorCode.NoError)
{
request.OnErrorOccured(assetDeliveryErrorCode);
return;
}
if (newState.Status == PlayCoreTranslator.AssetPackStatus.Canceled)
{
request.OnErrorOccured(AssetDeliveryErrorCode.Canceled);
return;
}
request.UpdateState(PlayCoreTranslator.TranslatePlayCorePackStatus(newState.Status),
newState.BytesDownloaded,
newState.TotalBytesToDownload);
}
private bool IsInstallTimeAssetBundle(string assetBundleName)
{
var packLocation = _assetPackManager.GetPackLocation(assetBundleName);
return packLocation != null && packLocation.PackStorageMethod == AssetPackStorageMethod.ApkAssets;
}
private ConfirmationDialogResult ConvertToConfirmationDialogResult(int resultCode)
{
ConfirmationDialogResult dialogResult;
switch (resultCode)
{
case ActivityResult.ResultOk:
dialogResult = ConfirmationDialogResult.Accepted;
break;
case ActivityResult.ResultCancelled:
dialogResult = ConfirmationDialogResult.Denied;
break;
default:
throw new NotImplementedException("Unexpected activity result: " + resultCode);
}
return dialogResult;
}
}
}

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 85b7e6bf8e3e4b8e91cbb5716761c9ed
timeCreated: 1583540802

View File

@@ -0,0 +1,95 @@
// Copyright 2020 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 System.Linq;
namespace Google.Play.AssetDelivery.Internal
{
public class PlayAssetPackBatchRequestImpl : PlayAssetPackBatchRequest
{
private readonly HashSet<string> _completedPackNames = new HashSet<string>();
internal PlayAssetPackBatchRequestImpl(IEnumerable<PlayAssetPackRequestImpl> requests)
{
Requests = requests.ToDictionary(request => request.AssetPackName,
request => request as PlayAssetPackRequest);
foreach (var entry in Requests)
{
entry.Value.Completed += OnChildPackCompleted;
}
}
public override event Action<PlayAssetPackBatchRequest> Completed
{
add
{
if (IsDone)
{
value.Invoke(this);
return;
}
base.Completed += value;
}
remove { base.Completed -= value; }
}
public void OnInitializedInPlayCore()
{
foreach (var request in Requests.Values)
{
var requestImpl = request as PlayAssetPackRequestImpl;
if (requestImpl == null)
{
throw new ArgumentException("Request is not a PlayAssetPackRequestImpl");
}
requestImpl.OnInitializedInPlayCore();
}
}
public void OnInitializationErrorOccurred(AssetDeliveryErrorCode errorCode)
{
foreach (var request in Requests.Values)
{
var requestImpl = request as PlayAssetPackRequestImpl;
if (requestImpl == null)
{
throw new ArgumentException("Request is not a PlayAssetPackRequestImpl");
}
requestImpl.OnErrorOccured(errorCode);
}
}
private void OnChildPackCompleted(PlayAssetPackRequest request)
{
var requestImpl = request as PlayAssetPackRequestImpl;
if (requestImpl == null)
{
throw new ArgumentException("Request is not a PlayAssetPackRequestImpl");
}
_completedPackNames.Add(requestImpl.AssetPackName);
if (_completedPackNames.Count == Requests.Count && !IsDone)
{
IsDone = true;
InvokeCompletedEvent();
}
}
}
}

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: a740d87a2bf1401bb24681935998ecd7
timeCreated: 1588812080

View File

@@ -0,0 +1,81 @@
// Copyright 2021 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.Collections.Generic;
using System.Linq;
using System.Text;
using Google.Play.Core.Internal;
using UnityEngine;
namespace Google.Play.AssetDelivery.Internal
{
/// <summary>
/// Wraps the subset of Play Core's AssetPackState that pertains to asset-only updates.
/// It contains information regarding newer versions of a particular asset pack.
/// </summary>
public class PlayAssetPackDownloadInfoImpl : PlayAssetPackDownloadInfo
{
/// <summary>
/// Creates a dictionary with download info, keyed by asset pack name, from the asset packs contained within a PlayCore
/// AssetPackStates object.
/// </summary>
/// <param name="javaAssetPackStates">
/// The PlayCore AssetPacksStates object containing the desired asset pack info.
/// </param>
/// <returns>
/// A dictionary, keyed by asset pack name, containing download info about the packs within the specified
/// AssetPackStates.
/// </returns>
public static IDictionary<string, PlayAssetPackDownloadInfo> FromAssetPackStates(
AndroidJavaObject javaAssetPackStates)
{
using (var javaMap = javaAssetPackStates.Call<AndroidJavaObject>("packStates"))
{
return PlayCoreHelper.ConvertJavaMap<string, AndroidJavaObject>(javaMap)
.ToDictionary<KeyValuePair<string, AndroidJavaObject>, string, PlayAssetPackDownloadInfo>(
kvp => kvp.Key,
kvp => new PlayAssetPackDownloadInfoImpl(kvp.Value));
}
}
/// <summary>
/// Creates a PlayAssetPackDownloadInfoImpl from the underlying Java AssetPackState.
/// Disposes the Java object in the process.
/// </summary>
/// <param name="javaAssetPackState">
/// The PlayCore AssetPackState Java object from which to create the PlayAssetPackDownloadInfoImpl.
/// </param>
public PlayAssetPackDownloadInfoImpl(AndroidJavaObject javaAssetPackState)
{
var javaAvailability = javaAssetPackState.Call<int>("updateAvailability");
UpdateAvailability = UpdateAvailabilityTranslator.TranslatePlayCoreUpdateAvailability(javaAvailability);
DownloadSize = javaAssetPackState.Call<long>("totalBytesToDownload");
AvailableVersionTag = javaAssetPackState.Call<string>("availableVersionTag");
InstalledVersionTag = javaAssetPackState.Call<string>("installedVersionTag");
javaAssetPackState.Dispose();
}
public override string ToString()
{
var stateDescription = new StringBuilder();
stateDescription.AppendFormat("update availability: {0}\n", UpdateAvailability);
stateDescription.AppendFormat("available version tag: {0}\n", AvailableVersionTag);
stateDescription.AppendFormat("installed version tag: {0}\n", InstalledVersionTag);
return stateDescription.ToString();
}
}
}

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: c3b4bb5ea9d44aa4a75c9cebdf74dc78
timeCreated: 1621899620

View File

@@ -0,0 +1,183 @@
// Copyright 2020 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.IO;
using Google.Play.Core.Internal;
using UnityEngine;
namespace Google.Play.AssetDelivery.Internal
{
internal class PlayAssetPackRequestImpl : PlayAssetPackRequest
{
public readonly string AssetPackName;
/// <summary>
/// The name of the folder within an asset pack containing all the pack's assets.
/// Asset packs packaged using the Unity packaging API will place all their assets under this folder.
/// </summary>
private const string AssetPackFolderName = "assetpack";
private readonly AssetPackManager _assetPackManager;
private bool _initializedInPlayCore;
private readonly PlayRequestRepository _requestRepository;
private Action _onInitializedInPlayCore = delegate { };
public PlayAssetPackRequestImpl(string assetPackName, AssetPackManager assetPackManager,
PlayRequestRepository requestRepository)
{
AssetPackName = assetPackName;
_assetPackManager = assetPackManager;
_requestRepository = requestRepository;
}
public override event Action<PlayAssetPackRequest> Completed
{
add
{
if (IsDone)
{
value.Invoke(this);
return;
}
base.Completed += value;
}
remove { base.Completed -= value; }
}
public void UpdateState(AssetDeliveryStatus status, long bytesDownloaded, long totalBytesToDownload)
{
if (totalBytesToDownload == 0L)
{
bool finishedDownloading = status == AssetDeliveryStatus.Available
|| status == AssetDeliveryStatus.Loading
|| status == AssetDeliveryStatus.Loaded;
DownloadProgress = finishedDownloading ? 1f : 0f;
}
else
{
DownloadProgress = bytesDownloaded / (float) totalBytesToDownload;
}
Status = status;
if (Status == AssetDeliveryStatus.Available)
{
OnPackAvailable();
}
}
public void OnInitializedInPlayCore()
{
// Execute on the main thread in case _onInitializedInPlayCore needs to check _requestRepository.
PlayCoreEventHandler.HandleEvent(() =>
{
_initializedInPlayCore = true;
_onInitializedInPlayCore();
});
}
public void OnPackAvailable()
{
Status = AssetDeliveryStatus.Available;
DownloadProgress = 1f;
if (!IsDone)
{
IsDone = true;
InvokeCompletedEvent();
}
}
public void OnErrorOccured(AssetDeliveryErrorCode errorCode)
{
if (IsDone)
{
return;
}
IsDone = true;
Error = errorCode;
Status = AssetDeliveryStatus.Failed;
InvokeCompletedEvent();
}
public override AssetBundleCreateRequest LoadAssetBundleAsync(string assetBundlePath)
{
var assetLocation = GetAssetLocation(assetBundlePath);
if (assetLocation == null)
{
// Check if the assetBundlePath was relative to "assets" path rather than to the "assets/assetpack"
// path. This may be a common error, so we check for it here and warn the developer.
if (AssetPackFolderName.Equals(assetBundlePath.Split('/')[0]))
{
Debug.LogError("Failed to find the asset at path {0} within the asset pack, possibly because the" +
" path begins with \"assetpack\".");
}
return null;
}
return AssetBundle.LoadFromFileAsync(assetLocation.Path, /* crc= */ 0, assetLocation.Offset);
}
public override AssetLocation GetAssetLocation(string assetPath)
{
var fullAssetPath = Path.Combine(AssetPackFolderName, assetPath);
return _assetPackManager.GetAssetLocation(AssetPackName, fullAssetPath);
}
public override void AttemptCancel()
{
if (IsDone || Status == AssetDeliveryStatus.Loaded)
{
return;
}
// If play core is aware of the associated pack, then we tell play core to cancel the pack download.
// Otherwise, we notify play core after the fetch task succeeds.
if (_initializedInPlayCore)
{
CancelPlayCore();
}
else
{
DeferCancelPlayCore();
}
OnErrorOccured(AssetDeliveryErrorCode.Canceled);
}
private void CancelPlayCore()
{
_assetPackManager.Cancel(AssetPackName).Dispose();
}
private void DeferCancelPlayCore()
{
_onInitializedInPlayCore = () =>
{
// Only cancel if a new request hasn't been started, to avoid cancelling the new request.
if (_requestRepository.ContainsRequest(AssetPackName))
{
Debug.LogFormat("Skip canceling {0}", AssetPackName);
}
else
{
CancelPlayCore();
}
};
}
}
}

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 24b88ac66b804124b880ad0b6b6f2dcc
timeCreated: 1588102816

View File

@@ -0,0 +1,131 @@
// 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;
namespace Google.Play.AssetDelivery.Internal
{
/// <summary>
/// Translates PlayCore's AssetPackErrorCode and AssetPackStatus Java enums into their corresponding public-facing
/// Unity enums.
/// </summary>
internal static class PlayCoreTranslator
{
private static class AssetPackErrorCode
{
public const int NoError = 0;
public const int AppUnavailable = -1;
public const int PackUnavailable = -2;
public const int InvalidRequest = -3;
public const int DownloadNotFound = -4;
public const int ApiNotAvailable = -5;
public const int NetworkError = -6;
public const int AccessDenied = -7;
public const int InsufficientStorage = -10;
public const int PlayStoreNotFound = -11;
public const int NetworkUnrestricted = -12;
public const int AppNotOwned = -13;
public const int ConfirmationNotRequired = -14;
public const int UnrecognizedInstallation = -15;
public const int InternalError = -100;
}
public static class AssetPackStatus
{
public const int Unknown = 0;
public const int Pending = 1;
public const int Downloading = 2;
public const int Transferring = 3;
public const int Completed = 4;
public const int Failed = 5;
public const int Canceled = 6;
public const int WaitingForWifi = 7;
public const int NotInstalled = 8;
public const int RequiresUserConfirmation = 9;
}
private static readonly Dictionary<int, AssetDeliveryErrorCode> PlayCoreToAssetDeliveryErrors =
new Dictionary<int, AssetDeliveryErrorCode>
{
{AssetPackErrorCode.NoError, AssetDeliveryErrorCode.NoError},
{AssetPackErrorCode.AppUnavailable, AssetDeliveryErrorCode.AppUnavailable},
{AssetPackErrorCode.PackUnavailable, AssetDeliveryErrorCode.BundleUnavailable},
{AssetPackErrorCode.InvalidRequest, AssetDeliveryErrorCode.InternalError},
{AssetPackErrorCode.ApiNotAvailable, AssetDeliveryErrorCode.InternalError},
{AssetPackErrorCode.DownloadNotFound, AssetDeliveryErrorCode.InternalError},
{AssetPackErrorCode.InternalError, AssetDeliveryErrorCode.InternalError},
{AssetPackErrorCode.NetworkError, AssetDeliveryErrorCode.NetworkError},
{AssetPackErrorCode.AccessDenied, AssetDeliveryErrorCode.AccessDenied},
{AssetPackErrorCode.InsufficientStorage, AssetDeliveryErrorCode.InsufficientStorage},
{AssetPackErrorCode.PlayStoreNotFound, AssetDeliveryErrorCode.PlayStoreNotFound},
{AssetPackErrorCode.NetworkUnrestricted, AssetDeliveryErrorCode.NetworkUnrestricted},
{AssetPackErrorCode.AppNotOwned, AssetDeliveryErrorCode.AppNotOwned},
{AssetPackErrorCode.ConfirmationNotRequired, AssetDeliveryErrorCode.ConfirmationNotRequired},
{AssetPackErrorCode.UnrecognizedInstallation, AssetDeliveryErrorCode.UnrecognizedInstallation},
};
private static readonly Dictionary<int, AssetDeliveryStatus> PlayCoreToAssetDeliveryStatuses
=
new Dictionary<int, AssetDeliveryStatus>
{
// Unity Asset Delivery requests are started immediately, so their status is Pending even if play core
// has not yet set its status to Pending.
{AssetPackStatus.NotInstalled, AssetDeliveryStatus.Pending},
{AssetPackStatus.Pending, AssetDeliveryStatus.Pending},
{AssetPackStatus.Downloading, AssetDeliveryStatus.Retrieving},
{AssetPackStatus.Transferring, AssetDeliveryStatus.Retrieving},
{AssetPackStatus.Completed, AssetDeliveryStatus.Available},
{AssetPackStatus.WaitingForWifi, AssetDeliveryStatus.WaitingForWifi},
{AssetPackStatus.RequiresUserConfirmation, AssetDeliveryStatus.RequiresUserConfirmation},
{AssetPackStatus.Failed, AssetDeliveryStatus.Failed},
{AssetPackStatus.Unknown, AssetDeliveryStatus.Failed},
{AssetPackStatus.Canceled, AssetDeliveryStatus.Failed},
};
/// <summary>
/// Translates Play Core's AssetPackErrorCode into its corresponding public-facing AssetDeliveryErrorCode.
/// </summary>
/// <exception cref="NotImplementedException">
/// Throws if the provided error code does not have a corresponding value in AssetDeliveryErrorCode.
/// </exception>
public static AssetDeliveryErrorCode TranslatePlayCoreErrorCode(int assetPackErrorCode)
{
AssetDeliveryErrorCode translatedErrorCode;
if (!PlayCoreToAssetDeliveryErrors.TryGetValue(assetPackErrorCode, out translatedErrorCode))
{
throw new NotImplementedException("Unexpected error code: " + assetPackErrorCode);
}
return translatedErrorCode;
}
/// <summary>
/// Translates Play Core's AssetPackStatus into its corresponding public-facing AssetDeliveryStatus.
/// </summary>
/// <exception cref="NotImplementedException">
/// Throws if the provided status does not have a corresponding value in AssetDeliveryStatus.
/// </exception>
public static AssetDeliveryStatus TranslatePlayCorePackStatus(int assetPackStatus)
{
AssetDeliveryStatus translatedStatus;
if (!PlayCoreToAssetDeliveryStatuses.TryGetValue(assetPackStatus, out translatedStatus))
{
throw new NotImplementedException("Unexpected pack status: " + assetPackStatus);
}
return translatedStatus;
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 560fb67e8b05948c8aa0b6314480534d
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,86 @@
// 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.Collections.Generic;
using System.Linq;
namespace Google.Play.AssetDelivery.Internal
{
/// <summary>
/// Repository for active requests related to Play Asset Delivery.
/// </summary>
internal class PlayRequestRepository
{
/// <summary>
/// Contains all active requests, including the <see cref="PlayAssetPackRequestImpl"/> contained within active
/// <see cref="PlayAssetBundleRequestImpl"/>.
/// </summary>
private Dictionary<string, PlayAssetPackRequestImpl> _requestsByName =
new Dictionary<string, PlayAssetPackRequestImpl>();
/// <summary>
/// Contains all active asset bundle requests. Every entry should have a corresponding entry in _requestsByName
/// for assetBundleRequest.PackRequest.
/// </summary>
private Dictionary<string, PlayAssetBundleRequestImpl> _assetBundleRequestsByName =
new Dictionary<string, PlayAssetBundleRequestImpl>();
public void AddAssetBundleRequest(PlayAssetBundleRequestImpl assetBundleRequest)
{
AddRequest(assetBundleRequest.PackRequest);
_assetBundleRequestsByName.Add(assetBundleRequest.PackRequest.AssetPackName, assetBundleRequest);
}
public void AddRequest(PlayAssetPackRequestImpl request)
{
_requestsByName.Add(request.AssetPackName, request);
}
public void RemoveRequest(string name)
{
_requestsByName.Remove(name);
_assetBundleRequestsByName.Remove(name);
}
public bool TryGetAssetBundleRequest(string name, out PlayAssetBundleRequestImpl assetBundleRequest)
{
return _assetBundleRequestsByName.TryGetValue(name, out assetBundleRequest);
}
public bool TryGetRequest(string name, out PlayAssetPackRequestImpl request)
{
return _requestsByName.TryGetValue(name, out request);
}
public IList<PlayAssetPackRequestImpl> GetRequestsWithStatus(AssetDeliveryStatus status)
{
return _requestsByName.Values.Where(request => request.Status == status).ToList();
}
public string[] GetActiveAssetPackNames()
{
return _requestsByName.Keys.ToArray();
}
public bool ContainsAssetBundleRequest(string name)
{
return _assetBundleRequestsByName.ContainsKey(name);
}
public bool ContainsRequest(string name)
{
return _requestsByName.ContainsKey(name);
}
}
}

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 9d8abdc8cf0340bbaae418da558de978
timeCreated: 1558390718

View File

@@ -0,0 +1,65 @@
// Copyright 2021 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;
namespace Google.Play.AssetDelivery.Internal
{
/// <summary>
/// Translates PlayCore's AssetPackUpdateAvailability Java enum into its corresponding public-facing
/// Unity enum.
/// </summary>
internal class UpdateAvailabilityTranslator
{
private static class PlayCoreAssetPackUpdateAvailability
{
public const int Unknown = 0;
public const int UpdateNotAvailable = 1;
public const int UpdateAvailable = 2;
}
private static readonly Dictionary<int, AssetPackUpdateAvailability> PlayCoreToAssetPackUpdateAvailability
=
new Dictionary<int, AssetPackUpdateAvailability>
{
{PlayCoreAssetPackUpdateAvailability.Unknown, AssetPackUpdateAvailability.Unknown},
{
PlayCoreAssetPackUpdateAvailability.UpdateNotAvailable,
AssetPackUpdateAvailability.UpdateNotAvailable
},
{PlayCoreAssetPackUpdateAvailability.UpdateAvailable, AssetPackUpdateAvailability.UpdateAvailable},
};
/// <summary>
/// Translates Play Core's AssetPackUpdateAvailability into its corresponding public-facing AssetPackUpdateAvailability.
/// </summary>
/// <exception cref="NotImplementedException">
/// Throws if the provided update availability does not have a corresponding value in AssetPackUpdateAvailability.
/// </exception>
public static AssetPackUpdateAvailability TranslatePlayCoreUpdateAvailability(
int assetPackUpdateAvailability)
{
AssetPackUpdateAvailability translatedAvailability;
if (!PlayCoreToAssetPackUpdateAvailability.TryGetValue(assetPackUpdateAvailability,
out translatedAvailability))
{
throw new NotImplementedException("Unexpected pack update availability: " +
assetPackUpdateAvailability);
}
return translatedAvailability;
}
}
}

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 686aee5c471041bba8bfb766b774885d
timeCreated: 1621899159