blob: eb6624a8fc3855ffb924ceff21ed8d281517aebd [file] [log] [blame]
/*
* Copyright (C) 2019 The Android Open Source Project
*
* 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
*
* http://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.
*/
package com.android.packageinstaller.role.ui;
import android.app.Application;
import android.content.pm.ApplicationInfo;
import android.os.Process;
import android.os.UserHandle;
import android.util.ArrayMap;
import android.util.Log;
import android.util.Pair;
import androidx.annotation.NonNull;
import androidx.lifecycle.AndroidViewModel;
import androidx.lifecycle.LifecycleOwner;
import androidx.lifecycle.LiveData;
import androidx.lifecycle.Transformations;
import androidx.lifecycle.ViewModel;
import androidx.lifecycle.ViewModelProvider;
import com.android.packageinstaller.role.model.Role;
import com.android.packageinstaller.role.utils.UserUtils;
import java.util.List;
/**
* {@link ViewModel} for a special app access.
*/
public class SpecialAppAccessViewModel extends AndroidViewModel {
private static final String LOG_TAG = SpecialAppAccessViewModel.class.getSimpleName();
@NonNull
private final Role mRole;
@NonNull
private final LiveData<List<Pair<ApplicationInfo, Boolean>>> mRoleLiveData;
@NonNull
private final ArrayMap<String, ManageRoleHolderStateLiveData> mManageRoleHolderStateLiveDatas =
new ArrayMap<>();
public SpecialAppAccessViewModel(@NonNull Role role, @NonNull Application application) {
super(application);
mRole = role;
UserHandle user = Process.myUserHandle();
RoleLiveData roleLiveData = new RoleLiveData(role, user, application);
UserHandle workProfile = UserUtils.getWorkProfile(application);
RoleSortFunction sortFunction = new RoleSortFunction(application);
if (workProfile == null) {
mRoleLiveData = Transformations.map(roleLiveData, sortFunction);
} else {
RoleLiveData workRoleLiveData = new RoleLiveData(role, workProfile, application);
mRoleLiveData = Transformations.map(new MergeRoleLiveData(roleLiveData,
workRoleLiveData), sortFunction);
}
}
@NonNull
public LiveData<List<Pair<ApplicationInfo, Boolean>>> getRoleLiveData() {
return mRoleLiveData;
}
/**
* Observe all the {@link ManageRoleHolderStateLiveData} instances.
*
* @param owner the {@link LifecycleOwner} which controls the observer
* @param observer the observer that will receive the events
*/
public void observeManageRoleHolderState(@NonNull LifecycleOwner owner,
@NonNull ManageRoleHolderStateObserver observer) {
int manageRoleHolderStateLiveDatasSize = mManageRoleHolderStateLiveDatas.size();
for (int i = 0; i < manageRoleHolderStateLiveDatasSize; i++) {
ManageRoleHolderStateLiveData liveData = mManageRoleHolderStateLiveDatas.valueAt(i);
liveData.observe(owner, state -> observer.onManageRoleHolderStateChanged(liveData,
state));
}
}
/**
* Get or create a {@link ManageRoleHolderStateLiveData} instance for the specified key.
*
* @param key the key for the {@link ManageRoleHolderStateLiveData}
* @param owner the {@link LifecycleOwner} which controls the observer
* @param observer the observer that will receive the events
*
* @return the {@link ManageRoleHolderStateLiveData}
*/
@NonNull
private ManageRoleHolderStateLiveData getManageRoleHolderStateLiveData(@NonNull String key,
@NonNull LifecycleOwner owner, @NonNull ManageRoleHolderStateObserver observer) {
ManageRoleHolderStateLiveData liveData = mManageRoleHolderStateLiveDatas.get(key);
if (liveData == null) {
liveData = new ManageRoleHolderStateLiveData();
ManageRoleHolderStateLiveData finalLiveData = liveData;
liveData.observe(owner, state -> observer.onManageRoleHolderStateChanged(finalLiveData,
state));
mManageRoleHolderStateLiveDatas.put(key, liveData);
}
return liveData;
}
/**
* Set whether an application has an special app access.
*
* @param packageName the package name of the application
* @param allow whether the application should have the access
* @param user the user of the application
* @param key the key for the {@link ManageRoleHolderStateLiveData}
* @param owner the {@link LifecycleOwner} which controls the observer
* @param observer the observer that will receive the events
*/
public void setSpecialAppAccessAsUser(@NonNull String packageName, boolean allow,
@NonNull UserHandle user, @NonNull String key, @NonNull LifecycleOwner owner,
@NonNull ManageRoleHolderStateObserver observer) {
ManageRoleHolderStateLiveData liveData = getManageRoleHolderStateLiveData(key, owner,
observer);
if (liveData.getValue() != ManageRoleHolderStateLiveData.STATE_IDLE) {
Log.i(LOG_TAG, "Trying to set special app access while another request is on-going");
return;
}
liveData.setRoleHolderAsUser(mRole.getName(), packageName, allow, 0, user,
getApplication());
}
/**
* Observer for multiple {@link ManageRoleHolderStateLiveData} instances.
*/
public interface ManageRoleHolderStateObserver {
/**
* Callback when any {@link ManageRoleHolderStateLiveData} changed.
*
* @param liveData the {@link ManageRoleHolderStateLiveData} that changed
* @param state the state after the change
*/
void onManageRoleHolderStateChanged(@NonNull ManageRoleHolderStateLiveData liveData,
int state);
}
/**
* {@link ViewModelProvider.Factory} for {@link SpecialAppAccessViewModel}.
*/
public static class Factory implements ViewModelProvider.Factory {
@NonNull
private Role mRole;
@NonNull
private Application mApplication;
public Factory(@NonNull Role role, @NonNull Application application) {
mRole = role;
mApplication = application;
}
@NonNull
@Override
public <T extends ViewModel> T create(@NonNull Class<T> modelClass) {
//noinspection unchecked
return (T) new SpecialAppAccessViewModel(mRole, mApplication);
}
}
}