1 /* 2 * Copyright (C) 2023 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.devicelockcontroller.activities; 18 19 import android.text.TextUtils; 20 21 import androidx.lifecycle.LiveData; 22 import androidx.lifecycle.MutableLiveData; 23 import androidx.lifecycle.ViewModel; 24 25 import com.android.devicelockcontroller.storage.SetupParametersClient; 26 import com.android.devicelockcontroller.util.LogUtil; 27 28 import com.google.common.util.concurrent.FutureCallback; 29 import com.google.common.util.concurrent.Futures; 30 import com.google.common.util.concurrent.ListenableFuture; 31 import com.google.common.util.concurrent.MoreExecutors; 32 33 /** 34 * A {@link ViewModel} which provides {@link ProvisioningProgress} to the 35 * {@link ProvisioningActivity}. 36 */ 37 public final class ProvisioningProgressViewModel extends ViewModel implements 38 ProvisioningProgressController { 39 40 private static final String TAG = "ProvisioningProgressViewModel"; 41 42 final MutableLiveData<String> mProviderNameLiveData; 43 final MutableLiveData<String> mSupportUrlLiveData; 44 private volatile boolean mAreProviderNameAndSupportUrlReady; 45 private final MutableLiveData<ProvisioningProgress> mProvisioningProgressLiveData; 46 private ProvisioningProgress mProvisioningProgress; 47 ProvisioningProgressViewModel()48 public ProvisioningProgressViewModel() { 49 mProviderNameLiveData = new MutableLiveData<>(); 50 mSupportUrlLiveData = new MutableLiveData<>(); 51 52 ListenableFuture<String> getKioskAppProviderNameFuture = 53 SetupParametersClient.getInstance().getKioskAppProviderName(); 54 Futures.addCallback( 55 getKioskAppProviderNameFuture, 56 new FutureCallback<>() { 57 @Override 58 public void onSuccess(String providerName) { 59 if (TextUtils.isEmpty(providerName)) { 60 LogUtil.e(TAG, "Device provider name is empty, should not reach here."); 61 return; 62 } 63 mProviderNameLiveData.postValue(providerName); 64 } 65 66 @Override 67 public void onFailure(Throwable t) { 68 LogUtil.e(TAG, "Failed to get Kiosk app provider name", t); 69 } 70 }, MoreExecutors.directExecutor()); 71 72 ListenableFuture<String> getSupportUrlFuture = 73 SetupParametersClient.getInstance().getSupportUrl(); 74 Futures.addCallback(getSupportUrlFuture, new FutureCallback<>() { 75 @Override 76 public void onSuccess(String supportUrl) { 77 mSupportUrlLiveData.postValue(supportUrl); 78 } 79 80 @Override 81 public void onFailure(Throwable t) { 82 LogUtil.e(TAG, "Failed to get support Url", t); 83 } 84 }, MoreExecutors.directExecutor()); 85 86 mProvisioningProgressLiveData = new MutableLiveData<>(); 87 ListenableFuture<?> result = Futures.whenAllSucceed(getKioskAppProviderNameFuture, 88 getSupportUrlFuture).run(() -> { 89 mAreProviderNameAndSupportUrlReady = true; 90 if (mProvisioningProgress != null) { 91 mProvisioningProgressLiveData.postValue(mProvisioningProgress); 92 } 93 }, MoreExecutors.directExecutor()); 94 Futures.addCallback(result, new FutureCallback<Object>() { 95 @Override 96 public void onSuccess(Object result) { 97 LogUtil.i(TAG, "Successfully updated provisioning progress live data"); 98 } 99 100 @Override 101 public void onFailure(Throwable t) { 102 throw new RuntimeException(t); 103 } 104 }, MoreExecutors.directExecutor()); 105 } 106 107 /** 108 * Returns the {@link LiveData} which provides the latest {@link ProvisioningProgress}. 109 * 110 * <p>Note, the caller of this method MUST NOT update the LiveData directly, use 111 * {@link #setProvisioningProgress} instead. 112 */ getProvisioningProgressLiveData()113 public LiveData<ProvisioningProgress> getProvisioningProgressLiveData() { 114 return mProvisioningProgressLiveData; 115 } 116 117 /** 118 * Set the {@link ProvisioningProgress} to the given state. 119 * 120 * <p>This method is thread-safe and can be called from any thread. 121 */ 122 @Override setProvisioningProgress(ProvisioningProgress provisioningProgress)123 public void setProvisioningProgress(ProvisioningProgress provisioningProgress) { 124 if (mAreProviderNameAndSupportUrlReady) { 125 LogUtil.d(TAG, "Updating ProvisioningProgress"); 126 mProvisioningProgress = provisioningProgress; 127 mProvisioningProgressLiveData.postValue(provisioningProgress); 128 } else { 129 LogUtil.d(TAG, 130 "The upstream LiveData is not ready yet, hold on until it completes"); 131 mProvisioningProgress = provisioningProgress; 132 } 133 } 134 } 135