1 /*
2  * Copyright (C) 2022 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.settings.applications;
18 
19 import android.Manifest;
20 import android.app.AppGlobals;
21 import android.app.job.JobScheduler;
22 import android.content.Context;
23 import android.content.pm.IPackageManager;
24 import android.os.RemoteException;
25 import android.os.UserHandle;
26 import android.util.Log;
27 
28 import com.android.internal.annotations.VisibleForTesting;
29 import com.android.internal.util.ArrayUtils;
30 import com.android.settingslib.applications.ApplicationsState;
31 import com.android.settingslib.applications.ApplicationsState.AppEntry;
32 import com.android.settingslib.applications.ApplicationsState.AppFilter;
33 
34 import libcore.util.EmptyArray;
35 
36 import java.util.List;
37 
38 /**
39  * Connects app op info to the ApplicationsState. Extends {@link AppStateAppOpsBridge} to tailor
40  * to the semantics of {@link Manifest.permission#RUN_USER_INITIATED_JOBS}.
41  * Also provides app filters that can use the info.
42  */
43 public class AppStateLongBackgroundTasksBridge extends AppStateBaseBridge {
44     private static final String PERMISSION = Manifest.permission.RUN_USER_INITIATED_JOBS;
45     private static final String TAG = "LongBackgroundTasksBridge";
46 
47     @VisibleForTesting
48     JobScheduler mJobScheduler;
49     @VisibleForTesting
50     String[] mRequesterPackages;
51 
AppStateLongBackgroundTasksBridge(Context context, ApplicationsState appState, Callback callback)52     public AppStateLongBackgroundTasksBridge(Context context, ApplicationsState appState,
53             Callback callback) {
54         super(appState, callback);
55 
56         mJobScheduler = context.getSystemService(JobScheduler.class);
57         final IPackageManager iPm = AppGlobals.getPackageManager();
58         try {
59             mRequesterPackages = iPm.getAppOpPermissionPackages(PERMISSION, context.getUserId());
60         } catch (RemoteException re) {
61             Log.e(TAG, "Cannot reach package manager", re);
62             mRequesterPackages = EmptyArray.STRING;
63         }
64     }
65 
66     /**
67      * Returns information regarding {@link Manifest.permission#RUN_USER_INITIATED_JOBS} for the
68      * given package and uid.
69      */
createPermissionState(String packageName, int uid)70     public LongBackgroundTasksState createPermissionState(String packageName, int uid) {
71         final int userId = UserHandle.getUserId(uid);
72 
73         final boolean permissionRequested = ArrayUtils.contains(mRequesterPackages, packageName);
74         final boolean permissionGranted = mJobScheduler.hasRunUserInitiatedJobsPermission(
75                 packageName, userId);
76         return new LongBackgroundTasksState(permissionRequested, permissionGranted);
77     }
78 
79     @Override
updateExtraInfo(AppEntry app, String pkg, int uid)80     protected void updateExtraInfo(AppEntry app, String pkg, int uid) {
81         app.extraInfo = createPermissionState(pkg, uid);
82     }
83 
84     @Override
loadAllExtraInfo()85     protected void loadAllExtraInfo() {
86         final List<AppEntry> allApps = mAppSession.getAllApps();
87         for (int i = 0; i < allApps.size(); i++) {
88             final AppEntry currentEntry = allApps.get(i);
89             updateExtraInfo(currentEntry, currentEntry.info.packageName, currentEntry.info.uid);
90         }
91     }
92 
93     public static final AppFilter FILTER_LONG_JOBS_APPS = new AppFilter() {
94 
95         @Override
96         public void init() {
97         }
98 
99         @Override
100         public boolean filterApp(AppEntry info) {
101             if (info.extraInfo instanceof LongBackgroundTasksState) {
102                 final LongBackgroundTasksState state = (LongBackgroundTasksState) info.extraInfo;
103                 return state.shouldBeVisible();
104             }
105             return false;
106         }
107     };
108 
109     /**
110      * Class to denote the state of an app regarding
111      * {@link Manifest.permission#RUN_USER_INITIATED_JOBS}.
112      */
113     public static class LongBackgroundTasksState {
114         private boolean mPermissionRequested;
115         private boolean mPermissionGranted;
116 
LongBackgroundTasksState(boolean permissionRequested, boolean permissionGranted)117         LongBackgroundTasksState(boolean permissionRequested, boolean permissionGranted) {
118             mPermissionRequested = permissionRequested;
119             mPermissionGranted = permissionGranted;
120         }
121 
122         /** Should the app associated with this state appear on the Settings screen */
shouldBeVisible()123         public boolean shouldBeVisible() {
124             return mPermissionRequested;
125         }
126 
127         /** Is the permission granted to the app associated with this state */
isAllowed()128         public boolean isAllowed() {
129             return mPermissionGranted;
130         }
131     }
132 }
133