1 /*
2  * Copyright (C) 2018 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.role.RoleManager;
20 import android.content.Context;
21 import android.os.UserHandle;
22 import android.util.Log;
23 
24 import androidx.annotation.NonNull;
25 import androidx.annotation.Nullable;
26 import androidx.lifecycle.LiveData;
27 
28 import java.util.concurrent.Executor;
29 import java.util.function.Consumer;
30 
31 /**
32  * {@link LiveData} for the state of managing a role holder.
33  */
34 public class ManageRoleHolderStateLiveData extends LiveData<Integer> {
35 
36     private static final String LOG_TAG = ManageRoleHolderStateLiveData.class.getSimpleName();
37 
38     private static final boolean DEBUG = false;
39 
40     public static final int STATE_IDLE = 0;
41     public static final int STATE_WORKING = 1;
42     public static final int STATE_SUCCESS = 2;
43     public static final int STATE_FAILURE = 3;
44 
45     @Nullable
46     private String mLastPackageName;
47     private boolean mLastAdd;
48     private int mLastFlags;
49     private UserHandle mLastUser;
50 
ManageRoleHolderStateLiveData()51     public ManageRoleHolderStateLiveData() {
52         setValue(STATE_IDLE);
53     }
54 
55     /**
56      * Set whether an application is a holder of a role, and update the state accordingly. Will
57      * be no-op if the current state is not {@link #STATE_IDLE}.
58      *
59      * @param roleName the name of the role
60      * @param packageName the package name of the application
61      * @param add whether to add or remove the application as a role holder
62      * @param flags optional behavior flags
63      * @param user the user to manage the role holder for
64      * @param context the {@code Context} to retrieve system services
65      */
setRoleHolderAsUser(@onNull String roleName, @NonNull String packageName, boolean add, int flags, @NonNull UserHandle user, @NonNull Context context)66     public void setRoleHolderAsUser(@NonNull String roleName, @NonNull String packageName,
67             boolean add, int flags, @NonNull UserHandle user, @NonNull Context context) {
68         if (getValue() != STATE_IDLE) {
69             Log.e(LOG_TAG, "Already (tried) managing role holders, requested role: " + roleName
70                     + ", requested package: " + packageName);
71             return;
72         }
73         if (DEBUG) {
74             Log.i(LOG_TAG, (add ? "Adding" : "Removing") + " package as role holder, role: "
75                     + roleName + ", package: " + packageName);
76         }
77         mLastPackageName = packageName;
78         mLastAdd = add;
79         mLastFlags = flags;
80         mLastUser = user;
81         setValue(STATE_WORKING);
82 
83         RoleManager roleManager = context.getSystemService(RoleManager.class);
84         Executor executor = context.getMainExecutor();
85         Consumer<Boolean> callback = successful -> {
86             if (successful) {
87                 if (DEBUG) {
88                     Log.i(LOG_TAG, "Package " + (add ? "added" : "removed")
89                             + " as role holder, role: " + roleName + ", package: " + packageName);
90                 }
91                 setValue(STATE_SUCCESS);
92             } else {
93                 if (DEBUG) {
94                     Log.i(LOG_TAG, "Failed to " + (add ? "add" : "remove")
95                             + " package as role holder, role: " + roleName + ", package: "
96                             + packageName);
97                 }
98                 setValue(STATE_FAILURE);
99             }
100         };
101         if (add) {
102             roleManager.addRoleHolderAsUser(roleName, packageName, flags, user, executor, callback);
103         } else {
104             roleManager.removeRoleHolderAsUser(roleName, packageName, flags, user, executor,
105                     callback);
106         }
107     }
108 
109     /**
110      * Clear the holders of a role, and update the state accordingly. Will be no-op if the current
111      * state is not {@link #STATE_IDLE}.
112      *
113      * @param roleName the name of the role
114      * @param flags optional behavior flags
115      * @param user the user to manage the role holder for
116      * @param context the {@code Context} to retrieve system services
117      */
clearRoleHoldersAsUser(@onNull String roleName, int flags, @NonNull UserHandle user, @NonNull Context context)118     public void clearRoleHoldersAsUser(@NonNull String roleName, int flags,
119             @NonNull UserHandle user, @NonNull Context context) {
120         if (getValue() != STATE_IDLE) {
121             Log.e(LOG_TAG, "Already (tried) managing role holders, requested role: " + roleName);
122             return;
123         }
124         if (DEBUG) {
125             Log.i(LOG_TAG, "Clearing role holders, role: " + roleName);
126         }
127         mLastPackageName = null;
128         mLastAdd = false;
129         mLastFlags = flags;
130         mLastUser = user;
131         setValue(STATE_WORKING);
132 
133         RoleManager roleManager = context.getSystemService(RoleManager.class);
134         Executor executor = context.getMainExecutor();
135         Consumer<Boolean> callback = successful -> {
136             if (successful) {
137                 if (DEBUG) {
138                     Log.i(LOG_TAG, "Cleared role holders, role: " + roleName);
139                 }
140                 setValue(STATE_SUCCESS);
141             } else {
142                 if (DEBUG) {
143                     Log.i(LOG_TAG, "Failed to clear role holders, role: " + roleName);
144                 }
145                 setValue(STATE_FAILURE);
146             }
147         };
148         roleManager.clearRoleHoldersAsUser(roleName, flags, user, executor, callback);
149     }
150 
151     @Nullable
getLastPackageName()152     public String getLastPackageName() {
153         return mLastPackageName;
154     }
155 
isLastAdd()156     public boolean isLastAdd() {
157         return mLastAdd;
158     }
159 
getLastFlags()160     public int getLastFlags() {
161         return mLastFlags;
162     }
163 
getLastUser()164     public UserHandle getLastUser() {
165         return mLastUser;
166     }
167 
168     /**
169      * Reset the state of this live data to {@link #STATE_IDLE}. Will be no-op if the current state
170      * is not {@link #STATE_SUCCESS} or {@link #STATE_FAILURE}.
171      */
resetState()172     public void resetState() {
173         int state = getValue();
174         if (!(state == STATE_SUCCESS || state == STATE_FAILURE)) {
175             Log.e(LOG_TAG, "Trying to reset state when the current state is not STATE_SUCCESS or"
176                     + " STATE_FAILURE");
177             return;
178         }
179         mLastPackageName = null;
180         mLastAdd = false;
181         mLastFlags = 0;
182         mLastUser = null;
183         setValue(STATE_IDLE);
184     }
185 }
186