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