1 /*
2  * Copyright (C) 2016 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 android.permissionpresenterservice;
18 
19 import android.annotation.SystemApi;
20 import android.app.Service;
21 import android.content.Context;
22 import android.content.Intent;
23 import android.content.pm.ApplicationInfo;
24 import android.content.pm.permission.IRuntimePermissionPresenter;
25 import android.content.pm.permission.RuntimePermissionPresentationInfo;
26 import android.content.pm.permission.RuntimePermissionPresenter;
27 import android.os.Bundle;
28 import android.os.Handler;
29 import android.os.IBinder;
30 import android.os.Looper;
31 import android.os.Message;
32 import android.os.RemoteCallback;
33 import com.android.internal.os.SomeArgs;
34 
35 import java.util.List;
36 
37 /**
38  * This service presents information regarding runtime permissions that is
39  * used for presenting them in the UI. Runtime permissions are presented as
40  * a single permission in the UI but may be composed of several individual
41  * permissions.
42  *
43  * @see RuntimePermissionPresenter
44  * @see RuntimePermissionPresentationInfo
45  *
46  * @hide
47  */
48 @SystemApi
49 public abstract class RuntimePermissionPresenterService extends Service {
50 
51     /**
52      * The {@link Intent} action that must be declared as handled by a service
53      * in its manifest for the system to recognize it as a runtime permission
54      * presenter service.
55      */
56     public static final String SERVICE_INTERFACE =
57             "android.permissionpresenterservice.RuntimePermissionPresenterService";
58 
59     // No need for locking - always set first and never modified
60     private Handler mHandler;
61 
62     @Override
attachBaseContext(Context base)63     public final void attachBaseContext(Context base) {
64         super.attachBaseContext(base);
65         mHandler = new MyHandler(base.getMainLooper());
66     }
67 
68     /**
69      * Gets the runtime permissions for an app.
70      *
71      * @param packageName The package for which to query.
72      */
onGetAppPermissions(String packageName)73     public abstract List<RuntimePermissionPresentationInfo> onGetAppPermissions(String packageName);
74 
75     @Override
onBind(Intent intent)76     public final IBinder onBind(Intent intent) {
77         return new IRuntimePermissionPresenter.Stub() {
78             @Override
79             public void getAppPermissions(String packageName, RemoteCallback callback) {
80                 SomeArgs args = SomeArgs.obtain();
81                 args.arg1 = packageName;
82                 args.arg2 = callback;
83                 mHandler.obtainMessage(MyHandler.MSG_GET_APP_PERMISSIONS,
84                         args).sendToTarget();
85             }
86         };
87     }
88 
89     private final class MyHandler extends Handler {
90         public static final int MSG_GET_APP_PERMISSIONS = 1;
91         public static final int MSG_GET_APPS_USING_PERMISSIONS = 2;
92 
93         public MyHandler(Looper looper) {
94             super(looper, null, false);
95         }
96 
97         @Override
98         public void handleMessage(Message msg) {
99             switch (msg.what) {
100                 case MSG_GET_APP_PERMISSIONS: {
101                     SomeArgs args = (SomeArgs) msg.obj;
102                     String packageName = (String) args.arg1;
103                     RemoteCallback callback = (RemoteCallback) args.arg2;
104                     args.recycle();
105                     List<RuntimePermissionPresentationInfo> permissions =
106                             onGetAppPermissions(packageName);
107                     if (permissions != null && !permissions.isEmpty()) {
108                         Bundle result = new Bundle();
109                         result.putParcelableList(RuntimePermissionPresenter.KEY_RESULT,
110                                 permissions);
111                         callback.sendResult(result);
112                     } else {
113                         callback.sendResult(null);
114                     }
115                 } break;
116             }
117         }
118     }
119 }
120