1 /* 2 * Copyright (C) 2019 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.packageinstaller.role.ui; 18 19 import android.app.Application; 20 import android.content.pm.ApplicationInfo; 21 import android.os.Process; 22 import android.os.UserHandle; 23 import android.util.ArrayMap; 24 import android.util.Log; 25 import android.util.Pair; 26 27 import androidx.annotation.NonNull; 28 import androidx.lifecycle.AndroidViewModel; 29 import androidx.lifecycle.LifecycleOwner; 30 import androidx.lifecycle.LiveData; 31 import androidx.lifecycle.Transformations; 32 import androidx.lifecycle.ViewModel; 33 import androidx.lifecycle.ViewModelProvider; 34 35 import com.android.packageinstaller.role.model.Role; 36 import com.android.packageinstaller.role.utils.UserUtils; 37 38 import java.util.List; 39 40 /** 41 * {@link ViewModel} for a special app access. 42 */ 43 public class SpecialAppAccessViewModel extends AndroidViewModel { 44 45 private static final String LOG_TAG = SpecialAppAccessViewModel.class.getSimpleName(); 46 47 @NonNull 48 private final Role mRole; 49 50 @NonNull 51 private final LiveData<List<Pair<ApplicationInfo, Boolean>>> mRoleLiveData; 52 53 @NonNull 54 private final ArrayMap<String, ManageRoleHolderStateLiveData> mManageRoleHolderStateLiveDatas = 55 new ArrayMap<>(); 56 SpecialAppAccessViewModel(@onNull Role role, @NonNull Application application)57 public SpecialAppAccessViewModel(@NonNull Role role, @NonNull Application application) { 58 super(application); 59 60 mRole = role; 61 62 UserHandle user = Process.myUserHandle(); 63 RoleLiveData roleLiveData = new RoleLiveData(role, user, application); 64 UserHandle workProfile = UserUtils.getWorkProfile(application); 65 RoleSortFunction sortFunction = new RoleSortFunction(application); 66 if (workProfile == null) { 67 mRoleLiveData = Transformations.map(roleLiveData, sortFunction); 68 } else { 69 RoleLiveData workRoleLiveData = new RoleLiveData(role, workProfile, application); 70 mRoleLiveData = Transformations.map(new MergeRoleLiveData(roleLiveData, 71 workRoleLiveData), sortFunction); 72 } 73 } 74 75 @NonNull getRoleLiveData()76 public LiveData<List<Pair<ApplicationInfo, Boolean>>> getRoleLiveData() { 77 return mRoleLiveData; 78 } 79 80 /** 81 * Observe all the {@link ManageRoleHolderStateLiveData} instances. 82 * 83 * @param owner the {@link LifecycleOwner} which controls the observer 84 * @param observer the observer that will receive the events 85 */ observeManageRoleHolderState(@onNull LifecycleOwner owner, @NonNull ManageRoleHolderStateObserver observer)86 public void observeManageRoleHolderState(@NonNull LifecycleOwner owner, 87 @NonNull ManageRoleHolderStateObserver observer) { 88 int manageRoleHolderStateLiveDatasSize = mManageRoleHolderStateLiveDatas.size(); 89 for (int i = 0; i < manageRoleHolderStateLiveDatasSize; i++) { 90 ManageRoleHolderStateLiveData liveData = mManageRoleHolderStateLiveDatas.valueAt(i); 91 92 liveData.observe(owner, state -> observer.onManageRoleHolderStateChanged(liveData, 93 state)); 94 } 95 } 96 97 /** 98 * Get or create a {@link ManageRoleHolderStateLiveData} instance for the specified key. 99 * 100 * @param key the key for the {@link ManageRoleHolderStateLiveData} 101 * @param owner the {@link LifecycleOwner} which controls the observer 102 * @param observer the observer that will receive the events 103 * 104 * @return the {@link ManageRoleHolderStateLiveData} 105 */ 106 @NonNull getManageRoleHolderStateLiveData(@onNull String key, @NonNull LifecycleOwner owner, @NonNull ManageRoleHolderStateObserver observer)107 private ManageRoleHolderStateLiveData getManageRoleHolderStateLiveData(@NonNull String key, 108 @NonNull LifecycleOwner owner, @NonNull ManageRoleHolderStateObserver observer) { 109 ManageRoleHolderStateLiveData liveData = mManageRoleHolderStateLiveDatas.get(key); 110 if (liveData == null) { 111 liveData = new ManageRoleHolderStateLiveData(); 112 ManageRoleHolderStateLiveData finalLiveData = liveData; 113 liveData.observe(owner, state -> observer.onManageRoleHolderStateChanged(finalLiveData, 114 state)); 115 mManageRoleHolderStateLiveDatas.put(key, liveData); 116 } 117 return liveData; 118 } 119 120 /** 121 * Set whether an application has an special app access. 122 * 123 * @param packageName the package name of the application 124 * @param allow whether the application should have the access 125 * @param user the user of the application 126 * @param key the key for the {@link ManageRoleHolderStateLiveData} 127 * @param owner the {@link LifecycleOwner} which controls the observer 128 * @param observer the observer that will receive the events 129 */ setSpecialAppAccessAsUser(@onNull String packageName, boolean allow, @NonNull UserHandle user, @NonNull String key, @NonNull LifecycleOwner owner, @NonNull ManageRoleHolderStateObserver observer)130 public void setSpecialAppAccessAsUser(@NonNull String packageName, boolean allow, 131 @NonNull UserHandle user, @NonNull String key, @NonNull LifecycleOwner owner, 132 @NonNull ManageRoleHolderStateObserver observer) { 133 ManageRoleHolderStateLiveData liveData = getManageRoleHolderStateLiveData(key, owner, 134 observer); 135 if (liveData.getValue() != ManageRoleHolderStateLiveData.STATE_IDLE) { 136 Log.i(LOG_TAG, "Trying to set special app access while another request is on-going"); 137 return; 138 } 139 liveData.setRoleHolderAsUser(mRole.getName(), packageName, allow, 0, user, 140 getApplication()); 141 } 142 143 /** 144 * Observer for multiple {@link ManageRoleHolderStateLiveData} instances. 145 */ 146 public interface ManageRoleHolderStateObserver { 147 148 /** 149 * Callback when any {@link ManageRoleHolderStateLiveData} changed. 150 * 151 * @param liveData the {@link ManageRoleHolderStateLiveData} that changed 152 * @param state the state after the change 153 */ onManageRoleHolderStateChanged(@onNull ManageRoleHolderStateLiveData liveData, int state)154 void onManageRoleHolderStateChanged(@NonNull ManageRoleHolderStateLiveData liveData, 155 int state); 156 } 157 158 /** 159 * {@link ViewModelProvider.Factory} for {@link SpecialAppAccessViewModel}. 160 */ 161 public static class Factory implements ViewModelProvider.Factory { 162 163 @NonNull 164 private Role mRole; 165 166 @NonNull 167 private Application mApplication; 168 Factory(@onNull Role role, @NonNull Application application)169 public Factory(@NonNull Role role, @NonNull Application application) { 170 mRole = role; 171 mApplication = application; 172 } 173 174 @NonNull 175 @Override create(@onNull Class<T> modelClass)176 public <T extends ViewModel> T create(@NonNull Class<T> modelClass) { 177 //noinspection unchecked 178 return (T) new SpecialAppAccessViewModel(mRole, mApplication); 179 } 180 } 181 } 182