// 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 Google.Play.Common;
using Google.Play.Core.Internal;
using UnityEngine;
namespace Google.Play.AppUpdate.Internal
{
///
/// Internal implementation of that wraps Play Core Java's methods through
/// and holds the , which is responsible for
/// monitoring OnStateUpdateEvents to forward state changes to object.
///
internal class AppUpdateManagerInternal
{
private readonly AppUpdateManagerPlayCore _appUpdateManagerPlayCore;
private readonly AppUpdateHandler _appUpdateHandler;
private AppUpdateRequestImpl _appUpdateRequest;
internal AppUpdateManagerInternal()
{
_appUpdateManagerPlayCore = new AppUpdateManagerPlayCore();
_appUpdateHandler = AppUpdateHandler.CreateInScene(this);
_appUpdateHandler.OnStateUpdateEvent += ProcessStateUpdate;
PlayCoreEventHandler.CreateInScene();
}
///
/// Wrapper around Play Core Java's getAppUpdateInfo() method.
///
///
/// A wrapped Play Core task, which will return an AndroidJavaObject representing an AppUpdateInfo.
/// The caller is responsible for disposing this task.
///
public PlayCoreTask GetAppUpdateInfo()
{
return _appUpdateManagerPlayCore.GetAppUpdateInfo();
}
///
/// An internal implementation that obtains an of AppUpdateInfo from Play Core
/// Java's getAppUpdateInfo() method and converts it to an internal .
///
///
/// A that
/// returns on successful callback
/// or returns on failure callback.
///
public PlayAsyncOperation GetAppUpdateInfoInternal()
{
var appUpdateAsyncOperation = new AppUpdateAsyncOperation();
var appUpdateInfoTask = GetAppUpdateInfo();
appUpdateInfoTask.RegisterOnSuccessCallback(javaUpdateInfo =>
{
appUpdateAsyncOperation.SetResult(new AppUpdateInfo(javaUpdateInfo));
appUpdateInfoTask.Dispose();
});
appUpdateInfoTask.RegisterOnFailureCallback((reason, errorCode) =>
{
appUpdateAsyncOperation.SetError(AppUpdatePlayCoreTranslator.TranslatePlayCoreErrorCode(errorCode));
appUpdateInfoTask.Dispose();
});
return appUpdateAsyncOperation;
}
///
/// Wrapper around Play Core Java's registerListener() method that receives state changes for self-update operations.
/// Listener should be subsequently cleared using .
///
/// An AndroidJavaProxy representing a java object of class:
/// com.google.android.play.core.appupdate.InstallStateUpdatedListener
///
public void RegisterListener(AndroidJavaProxy listener)
{
_appUpdateManagerPlayCore.RegisterListener(listener);
}
///
/// Wrapper around Play Core Java's unregisterListener() method that removes the specified listener previously
/// added using .
///
/// An AndroidJavaProxy representing a java object of class:
/// com.google.android.play.core.appupdate.InstallStateUpdatedListener
///
public void UnregisterListener(AndroidJavaProxy listener)
{
_appUpdateManagerPlayCore.UnregisterListener(listener);
}
///
/// Creates an that can be used to monitor the update progress and start the
/// desired update flow indicated by .
///
/// The on success result of .
/// contains update type options.
///
/// A which can be used to monitor the asynchronous request of an update flow.
///
///
/// Throws if any of the the provided parameters are null.
///
///
/// Throws if there is already an in progress.
///
public AppUpdateRequest StartUpdateInternal(AppUpdateInfo appUpdateInfo, AppUpdateOptions appUpdateOptions)
{
if (appUpdateInfo == null)
{
throw new ArgumentNullException("appUpdateInfo");
}
if (appUpdateOptions == null)
{
throw new ArgumentNullException("appUpdateOptions");
}
if (_appUpdateRequest != null)
{
throw new InvalidOperationException(
"Another update flow is already in progress.");
}
_appUpdateRequest = new AppUpdateRequestImpl();
if (appUpdateInfo.UpdateAvailability == UpdateAvailability.UpdateNotAvailable)
{
_appUpdateRequest.OnErrorOccurred(AppUpdateErrorCode.ErrorUpdateUnavailable);
return _appUpdateRequest;
}
if (!appUpdateInfo.IsUpdateTypeAllowed(appUpdateOptions))
{
_appUpdateRequest.OnErrorOccurred(AppUpdateErrorCode.ErrorUpdateNotAllowed);
return _appUpdateRequest;
}
_appUpdateRequest.Completed += (req) => { _appUpdateRequest = null; };
InitiateRequest(_appUpdateRequest, appUpdateInfo, appUpdateOptions);
return _appUpdateRequest;
}
///
/// An internal implementation that wraps Play Core Java's completeUpdate() method that triggers the completion
/// of the update for a flexible update flow.
///
///
/// A that returns an
/// on failure.
/// If the update succeeds, the app restarts and this callback never fires.
///
public PlayAsyncOperation CompleteUpdateInternal()
{
var completeUpdateAsyncOperation = new AppUpdateAsyncOperation();
var completeUpdateTask = _appUpdateManagerPlayCore.CompleteUpdate();
completeUpdateTask.RegisterOnSuccessCallback(voidResult =>
{
completeUpdateAsyncOperation.SetResult(voidResult);
completeUpdateTask.Dispose();
});
completeUpdateTask.RegisterOnFailureCallback((reason, errorCode) =>
{
completeUpdateAsyncOperation.SetError(
AppUpdatePlayCoreTranslator.TranslatePlayCoreErrorCode(errorCode));
completeUpdateTask.Dispose();
});
return completeUpdateAsyncOperation;
}
private void InitiateRequest(AppUpdateRequestImpl request, AppUpdateInfo appUpdateInfo,
AppUpdateOptions appUpdateOptions)
{
if (appUpdateInfo.UpdateAvailability == UpdateAvailability.DeveloperTriggeredUpdateInProgress)
{
// If an update is already in progress, it would skip user confirmation dialog and
// the ActivityResult for user confirmation should be set to ResultOk.
request.SetUpdateActivityResult(ActivityResult.ResultOk);
}
if (request.IsDone && appUpdateOptions.AppUpdateType == AppUpdateType.Flexible)
{
request.OnUpdateDownloaded();
}
else
{
var requestFlowTask = _appUpdateManagerPlayCore.StartUpdateFlow(appUpdateInfo, appUpdateOptions);
requestFlowTask.RegisterOnSuccessCallback(resultCode =>
{
// Set user confirmation dialog result for the update request.
request.SetUpdateActivityResult(resultCode);
requestFlowTask.Dispose();
});
requestFlowTask.RegisterOnFailureCallback((reason, errorCode) =>
{
Debug.LogErrorFormat("Update flow request failed: {0}", errorCode);
request.OnErrorOccurred(AppUpdatePlayCoreTranslator.TranslatePlayCoreErrorCode(errorCode));
requestFlowTask.Dispose();
});
}
}
private void ProcessStateUpdate(AppUpdateState newState)
{
if (_appUpdateRequest != null && newState != null)
{
AppUpdateRequest(_appUpdateRequest, newState);
}
}
private void AppUpdateRequest(AppUpdateRequestImpl request, AppUpdateState newState)
{
if (AppUpdatePlayCoreTranslator.TranslatePlayCoreErrorCode(newState.ErrorCode) !=
AppUpdateErrorCode.NoError)
{
request.OnErrorOccurred(request.Error);
return;
}
request.UpdateState(AppUpdatePlayCoreTranslator.TranslatePlayCoreUpdateStatus(newState.Status),
newState.BytesDownloaded,
newState.TotalBytesToDownload);
}
}
}