1ae0e03a9e03de34e37b768b971d7596d7220a053Svet Ganov/*
2ae0e03a9e03de34e37b768b971d7596d7220a053Svet Ganov * Copyright (C) 2016 The Android Open Source Project
3ae0e03a9e03de34e37b768b971d7596d7220a053Svet Ganov *
4ae0e03a9e03de34e37b768b971d7596d7220a053Svet Ganov * Licensed under the Apache License, Version 2.0 (the "License");
5ae0e03a9e03de34e37b768b971d7596d7220a053Svet Ganov * you may not use this file except in compliance with the License.
6ae0e03a9e03de34e37b768b971d7596d7220a053Svet Ganov * You may obtain a copy of the License at
7ae0e03a9e03de34e37b768b971d7596d7220a053Svet Ganov *
8ae0e03a9e03de34e37b768b971d7596d7220a053Svet Ganov *      http://www.apache.org/licenses/LICENSE-2.0
9ae0e03a9e03de34e37b768b971d7596d7220a053Svet Ganov *
10ae0e03a9e03de34e37b768b971d7596d7220a053Svet Ganov * Unless required by applicable law or agreed to in writing, software
11ae0e03a9e03de34e37b768b971d7596d7220a053Svet Ganov * distributed under the License is distributed on an "AS IS" BASIS,
12ae0e03a9e03de34e37b768b971d7596d7220a053Svet Ganov * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13ae0e03a9e03de34e37b768b971d7596d7220a053Svet Ganov * See the License for the specific language governing permissions and
14ae0e03a9e03de34e37b768b971d7596d7220a053Svet Ganov * limitations under the License.
15ae0e03a9e03de34e37b768b971d7596d7220a053Svet Ganov */
16ae0e03a9e03de34e37b768b971d7596d7220a053Svet Ganov
17ae0e03a9e03de34e37b768b971d7596d7220a053Svet Ganovpackage android.content.pm.permission;
18ae0e03a9e03de34e37b768b971d7596d7220a053Svet Ganov
19ae0e03a9e03de34e37b768b971d7596d7220a053Svet Ganovimport android.annotation.NonNull;
20ae0e03a9e03de34e37b768b971d7596d7220a053Svet Ganovimport android.annotation.Nullable;
21ae0e03a9e03de34e37b768b971d7596d7220a053Svet Ganovimport android.content.ComponentName;
22ae0e03a9e03de34e37b768b971d7596d7220a053Svet Ganovimport android.content.Context;
23ae0e03a9e03de34e37b768b971d7596d7220a053Svet Ganovimport android.content.Intent;
24ae0e03a9e03de34e37b768b971d7596d7220a053Svet Ganovimport android.content.ServiceConnection;
25ae0e03a9e03de34e37b768b971d7596d7220a053Svet Ganovimport android.content.pm.ApplicationInfo;
26ae0e03a9e03de34e37b768b971d7596d7220a053Svet Ganovimport android.os.Bundle;
27ae0e03a9e03de34e37b768b971d7596d7220a053Svet Ganovimport android.os.Handler;
28ae0e03a9e03de34e37b768b971d7596d7220a053Svet Ganovimport android.os.IBinder;
29ae0e03a9e03de34e37b768b971d7596d7220a053Svet Ganovimport android.os.Message;
30ae0e03a9e03de34e37b768b971d7596d7220a053Svet Ganovimport android.os.RemoteCallback;
31ae0e03a9e03de34e37b768b971d7596d7220a053Svet Ganovimport android.os.RemoteException;
32ae0e03a9e03de34e37b768b971d7596d7220a053Svet Ganovimport android.permissionpresenterservice.RuntimePermissionPresenterService;
33ae0e03a9e03de34e37b768b971d7596d7220a053Svet Ganovimport android.util.Log;
34ae0e03a9e03de34e37b768b971d7596d7220a053Svet Ganovimport com.android.internal.annotations.GuardedBy;
35ae0e03a9e03de34e37b768b971d7596d7220a053Svet Ganovimport com.android.internal.os.SomeArgs;
36ae0e03a9e03de34e37b768b971d7596d7220a053Svet Ganov
37ae0e03a9e03de34e37b768b971d7596d7220a053Svet Ganovimport java.util.ArrayList;
38ae0e03a9e03de34e37b768b971d7596d7220a053Svet Ganovimport java.util.Collections;
39ae0e03a9e03de34e37b768b971d7596d7220a053Svet Ganovimport java.util.List;
40ae0e03a9e03de34e37b768b971d7596d7220a053Svet Ganov
41ae0e03a9e03de34e37b768b971d7596d7220a053Svet Ganov/**
42ae0e03a9e03de34e37b768b971d7596d7220a053Svet Ganov * This class provides information about runtime permissions for a specific
43ae0e03a9e03de34e37b768b971d7596d7220a053Svet Ganov * app or all apps. This information is dedicated for presentation purposes
44ae0e03a9e03de34e37b768b971d7596d7220a053Svet Ganov * and does not necessarily reflect the individual permissions requested/
45ae0e03a9e03de34e37b768b971d7596d7220a053Svet Ganov * granted to an app as the platform may be grouping permissions to improve
46ae0e03a9e03de34e37b768b971d7596d7220a053Svet Ganov * presentation and help the user make an informed choice. For example, all
47ae0e03a9e03de34e37b768b971d7596d7220a053Svet Ganov * runtime permissions in the same permission group may be presented as a
48ae0e03a9e03de34e37b768b971d7596d7220a053Svet Ganov * single permission in the UI.
49ae0e03a9e03de34e37b768b971d7596d7220a053Svet Ganov *
50ae0e03a9e03de34e37b768b971d7596d7220a053Svet Ganov * @hide
51ae0e03a9e03de34e37b768b971d7596d7220a053Svet Ganov */
52ae0e03a9e03de34e37b768b971d7596d7220a053Svet Ganovpublic final class RuntimePermissionPresenter {
53ae0e03a9e03de34e37b768b971d7596d7220a053Svet Ganov    private static final String TAG = "RuntimePermPresenter";
54ae0e03a9e03de34e37b768b971d7596d7220a053Svet Ganov
55ae0e03a9e03de34e37b768b971d7596d7220a053Svet Ganov    /**
56ae0e03a9e03de34e37b768b971d7596d7220a053Svet Ganov     * The key for retrieving the result from the returned bundle.
57ae0e03a9e03de34e37b768b971d7596d7220a053Svet Ganov     *
58ae0e03a9e03de34e37b768b971d7596d7220a053Svet Ganov     * @hide
59ae0e03a9e03de34e37b768b971d7596d7220a053Svet Ganov     */
60ae0e03a9e03de34e37b768b971d7596d7220a053Svet Ganov    public static final String KEY_RESULT =
61ae0e03a9e03de34e37b768b971d7596d7220a053Svet Ganov            "android.content.pm.permission.RuntimePermissionPresenter.key.result";
62ae0e03a9e03de34e37b768b971d7596d7220a053Svet Ganov
63ae0e03a9e03de34e37b768b971d7596d7220a053Svet Ganov    /**
64ae0e03a9e03de34e37b768b971d7596d7220a053Svet Ganov     * Listener for delivering a result.
65ae0e03a9e03de34e37b768b971d7596d7220a053Svet Ganov     */
66ae0e03a9e03de34e37b768b971d7596d7220a053Svet Ganov    public static abstract class OnResultCallback {
67ae0e03a9e03de34e37b768b971d7596d7220a053Svet Ganov        /**
68ae0e03a9e03de34e37b768b971d7596d7220a053Svet Ganov         * The result for {@link #getAppPermissions(String, OnResultCallback, Handler)}.
69ae0e03a9e03de34e37b768b971d7596d7220a053Svet Ganov         * @param permissions The permissions list.
70ae0e03a9e03de34e37b768b971d7596d7220a053Svet Ganov         */
71ae0e03a9e03de34e37b768b971d7596d7220a053Svet Ganov        public void onGetAppPermissions(@NonNull
72ae0e03a9e03de34e37b768b971d7596d7220a053Svet Ganov                List<RuntimePermissionPresentationInfo> permissions) {
73ae0e03a9e03de34e37b768b971d7596d7220a053Svet Ganov            /* do nothing - stub */
74ae0e03a9e03de34e37b768b971d7596d7220a053Svet Ganov        }
75ae0e03a9e03de34e37b768b971d7596d7220a053Svet Ganov
76ae0e03a9e03de34e37b768b971d7596d7220a053Svet Ganov        /**
77ae0e03a9e03de34e37b768b971d7596d7220a053Svet Ganov         * The result for {@link #getAppsUsingPermissions(boolean, List)}.
78ae0e03a9e03de34e37b768b971d7596d7220a053Svet Ganov         * @param system Whether to return only the system apps or only the non-system ones.
79ae0e03a9e03de34e37b768b971d7596d7220a053Svet Ganov         * @param apps The apps using runtime permissions.
80ae0e03a9e03de34e37b768b971d7596d7220a053Svet Ganov         */
81ae0e03a9e03de34e37b768b971d7596d7220a053Svet Ganov        public void getAppsUsingPermissions(boolean system, @NonNull List<ApplicationInfo> apps) {
82ae0e03a9e03de34e37b768b971d7596d7220a053Svet Ganov            /* do nothing - stub */
83ae0e03a9e03de34e37b768b971d7596d7220a053Svet Ganov        }
84ae0e03a9e03de34e37b768b971d7596d7220a053Svet Ganov    }
85ae0e03a9e03de34e37b768b971d7596d7220a053Svet Ganov
86ae0e03a9e03de34e37b768b971d7596d7220a053Svet Ganov    private static final Object sLock = new Object();
87ae0e03a9e03de34e37b768b971d7596d7220a053Svet Ganov
88ae0e03a9e03de34e37b768b971d7596d7220a053Svet Ganov    @GuardedBy("sLock")
89ae0e03a9e03de34e37b768b971d7596d7220a053Svet Ganov    private static RuntimePermissionPresenter sInstance;
90ae0e03a9e03de34e37b768b971d7596d7220a053Svet Ganov
91ae0e03a9e03de34e37b768b971d7596d7220a053Svet Ganov    private final RemoteService mRemoteService;
92ae0e03a9e03de34e37b768b971d7596d7220a053Svet Ganov
93ae0e03a9e03de34e37b768b971d7596d7220a053Svet Ganov    /**
94ae0e03a9e03de34e37b768b971d7596d7220a053Svet Ganov     * Gets the singleton runtime permission presenter.
95ae0e03a9e03de34e37b768b971d7596d7220a053Svet Ganov     *
96ae0e03a9e03de34e37b768b971d7596d7220a053Svet Ganov     * @param context Context for accessing resources.
97ae0e03a9e03de34e37b768b971d7596d7220a053Svet Ganov     * @return The singleton instance.
98ae0e03a9e03de34e37b768b971d7596d7220a053Svet Ganov     */
99ae0e03a9e03de34e37b768b971d7596d7220a053Svet Ganov    public static RuntimePermissionPresenter getInstance(@NonNull Context context) {
100ae0e03a9e03de34e37b768b971d7596d7220a053Svet Ganov        synchronized (sLock) {
101ae0e03a9e03de34e37b768b971d7596d7220a053Svet Ganov            if (sInstance == null) {
102ae0e03a9e03de34e37b768b971d7596d7220a053Svet Ganov                sInstance = new RuntimePermissionPresenter(context.getApplicationContext());
103ae0e03a9e03de34e37b768b971d7596d7220a053Svet Ganov            }
104ae0e03a9e03de34e37b768b971d7596d7220a053Svet Ganov            return sInstance;
105ae0e03a9e03de34e37b768b971d7596d7220a053Svet Ganov        }
106ae0e03a9e03de34e37b768b971d7596d7220a053Svet Ganov    }
107ae0e03a9e03de34e37b768b971d7596d7220a053Svet Ganov
108ae0e03a9e03de34e37b768b971d7596d7220a053Svet Ganov    private RuntimePermissionPresenter(Context context) {
109ae0e03a9e03de34e37b768b971d7596d7220a053Svet Ganov        mRemoteService = new RemoteService(context);
110ae0e03a9e03de34e37b768b971d7596d7220a053Svet Ganov    }
111ae0e03a9e03de34e37b768b971d7596d7220a053Svet Ganov
112ae0e03a9e03de34e37b768b971d7596d7220a053Svet Ganov    /**
113ae0e03a9e03de34e37b768b971d7596d7220a053Svet Ganov     * Gets the runtime permissions for an app.
114ae0e03a9e03de34e37b768b971d7596d7220a053Svet Ganov     *
115ae0e03a9e03de34e37b768b971d7596d7220a053Svet Ganov     * @param packageName The package for which to query.
116ae0e03a9e03de34e37b768b971d7596d7220a053Svet Ganov     * @param callback Callback to receive the result.
117ae0e03a9e03de34e37b768b971d7596d7220a053Svet Ganov     * @param handler Handler on which to invoke the callback.
118ae0e03a9e03de34e37b768b971d7596d7220a053Svet Ganov     */
119ae0e03a9e03de34e37b768b971d7596d7220a053Svet Ganov    public void getAppPermissions(@NonNull String packageName,
120ae0e03a9e03de34e37b768b971d7596d7220a053Svet Ganov            @NonNull OnResultCallback callback, @Nullable Handler handler) {
121ae0e03a9e03de34e37b768b971d7596d7220a053Svet Ganov        SomeArgs args = SomeArgs.obtain();
122ae0e03a9e03de34e37b768b971d7596d7220a053Svet Ganov        args.arg1 = packageName;
123ae0e03a9e03de34e37b768b971d7596d7220a053Svet Ganov        args.arg2 = callback;
124ae0e03a9e03de34e37b768b971d7596d7220a053Svet Ganov        args.arg3 = handler;
125ae0e03a9e03de34e37b768b971d7596d7220a053Svet Ganov        Message message = mRemoteService.obtainMessage(
126ae0e03a9e03de34e37b768b971d7596d7220a053Svet Ganov                RemoteService.MSG_GET_APP_PERMISSIONS, args);
127ae0e03a9e03de34e37b768b971d7596d7220a053Svet Ganov        mRemoteService.processMessage(message);
128ae0e03a9e03de34e37b768b971d7596d7220a053Svet Ganov    }
129ae0e03a9e03de34e37b768b971d7596d7220a053Svet Ganov
130ae0e03a9e03de34e37b768b971d7596d7220a053Svet Ganov    /**
131ae0e03a9e03de34e37b768b971d7596d7220a053Svet Ganov     * Gets the system apps that use runtime permissions. System apps are ones
132ae0e03a9e03de34e37b768b971d7596d7220a053Svet Ganov     * that are considered system for presentation purposes instead of ones
133ae0e03a9e03de34e37b768b971d7596d7220a053Svet Ganov     * that are preinstalled on the system image. System apps are ones that
134ae0e03a9e03de34e37b768b971d7596d7220a053Svet Ganov     * are on the system image, haven't been updated (a.k.a factory apps)
135ae0e03a9e03de34e37b768b971d7596d7220a053Svet Ganov     * that do not have a launcher icon.
136ae0e03a9e03de34e37b768b971d7596d7220a053Svet Ganov     *
137ae0e03a9e03de34e37b768b971d7596d7220a053Svet Ganov     * @param system If true only system apps are returned otherwise only
138ae0e03a9e03de34e37b768b971d7596d7220a053Svet Ganov     *        non-system ones are returned.
139ae0e03a9e03de34e37b768b971d7596d7220a053Svet Ganov     * @param callback Callback to receive the result.
140ae0e03a9e03de34e37b768b971d7596d7220a053Svet Ganov     * @param handler Handler on which to invoke the callback.
141ae0e03a9e03de34e37b768b971d7596d7220a053Svet Ganov     */
142ae0e03a9e03de34e37b768b971d7596d7220a053Svet Ganov    public void getAppsUsingPermissions(boolean system, @NonNull OnResultCallback callback,
143ae0e03a9e03de34e37b768b971d7596d7220a053Svet Ganov            @Nullable Handler handler) {
144ae0e03a9e03de34e37b768b971d7596d7220a053Svet Ganov        SomeArgs args = SomeArgs.obtain();
145ae0e03a9e03de34e37b768b971d7596d7220a053Svet Ganov        args.arg1 = callback;
146ae0e03a9e03de34e37b768b971d7596d7220a053Svet Ganov        args.arg2 = handler;
147ae0e03a9e03de34e37b768b971d7596d7220a053Svet Ganov        args.argi1 = system ? 1 : 0;
148ae0e03a9e03de34e37b768b971d7596d7220a053Svet Ganov        Message message = mRemoteService.obtainMessage(
149ae0e03a9e03de34e37b768b971d7596d7220a053Svet Ganov                RemoteService.MSG_GET_APPS_USING_PERMISSIONS, args);
150ae0e03a9e03de34e37b768b971d7596d7220a053Svet Ganov        mRemoteService.processMessage(message);
151ae0e03a9e03de34e37b768b971d7596d7220a053Svet Ganov    }
152ae0e03a9e03de34e37b768b971d7596d7220a053Svet Ganov
153ae0e03a9e03de34e37b768b971d7596d7220a053Svet Ganov    private static final class RemoteService
154ae0e03a9e03de34e37b768b971d7596d7220a053Svet Ganov            extends Handler implements ServiceConnection {
155ae0e03a9e03de34e37b768b971d7596d7220a053Svet Ganov        private static final long UNBIND_TIMEOUT_MILLIS = 10000;
156ae0e03a9e03de34e37b768b971d7596d7220a053Svet Ganov
157ae0e03a9e03de34e37b768b971d7596d7220a053Svet Ganov        public static final int MSG_GET_APP_PERMISSIONS = 1;
158ae0e03a9e03de34e37b768b971d7596d7220a053Svet Ganov        public static final int MSG_GET_APPS_USING_PERMISSIONS = 2;
159ae0e03a9e03de34e37b768b971d7596d7220a053Svet Ganov        public static final int MSG_UNBIND = 3;
160ae0e03a9e03de34e37b768b971d7596d7220a053Svet Ganov
161ae0e03a9e03de34e37b768b971d7596d7220a053Svet Ganov        private final Object mLock = new Object();
162ae0e03a9e03de34e37b768b971d7596d7220a053Svet Ganov
163ae0e03a9e03de34e37b768b971d7596d7220a053Svet Ganov        private final Context mContext;
164ae0e03a9e03de34e37b768b971d7596d7220a053Svet Ganov
165ae0e03a9e03de34e37b768b971d7596d7220a053Svet Ganov        @GuardedBy("mLock")
166ae0e03a9e03de34e37b768b971d7596d7220a053Svet Ganov        private final List<Message> mPendingWork = new ArrayList<>();
167ae0e03a9e03de34e37b768b971d7596d7220a053Svet Ganov
168ae0e03a9e03de34e37b768b971d7596d7220a053Svet Ganov        @GuardedBy("mLock")
169ae0e03a9e03de34e37b768b971d7596d7220a053Svet Ganov        private IRuntimePermissionPresenter mRemoteInstance;
170ae0e03a9e03de34e37b768b971d7596d7220a053Svet Ganov
171ae0e03a9e03de34e37b768b971d7596d7220a053Svet Ganov        @GuardedBy("mLock")
172ae0e03a9e03de34e37b768b971d7596d7220a053Svet Ganov        private boolean mBound;
173ae0e03a9e03de34e37b768b971d7596d7220a053Svet Ganov
174ae0e03a9e03de34e37b768b971d7596d7220a053Svet Ganov        public RemoteService(Context context) {
175ae0e03a9e03de34e37b768b971d7596d7220a053Svet Ganov            super(context.getMainLooper(), null, false);
176ae0e03a9e03de34e37b768b971d7596d7220a053Svet Ganov            mContext = context;
177ae0e03a9e03de34e37b768b971d7596d7220a053Svet Ganov        }
178ae0e03a9e03de34e37b768b971d7596d7220a053Svet Ganov
179ae0e03a9e03de34e37b768b971d7596d7220a053Svet Ganov        public void processMessage(Message message) {
180ae0e03a9e03de34e37b768b971d7596d7220a053Svet Ganov            synchronized (mLock) {
181ae0e03a9e03de34e37b768b971d7596d7220a053Svet Ganov                if (!mBound) {
182ae0e03a9e03de34e37b768b971d7596d7220a053Svet Ganov                    Intent intent = new Intent(
183ae0e03a9e03de34e37b768b971d7596d7220a053Svet Ganov                            RuntimePermissionPresenterService.SERVICE_INTERFACE);
184ae0e03a9e03de34e37b768b971d7596d7220a053Svet Ganov                    intent.setPackage(mContext.getPackageManager()
185ae0e03a9e03de34e37b768b971d7596d7220a053Svet Ganov                            .getPermissionControllerPackageName());
186ae0e03a9e03de34e37b768b971d7596d7220a053Svet Ganov                    mBound = mContext.bindService(intent, this,
187ae0e03a9e03de34e37b768b971d7596d7220a053Svet Ganov                            Context.BIND_AUTO_CREATE);
188ae0e03a9e03de34e37b768b971d7596d7220a053Svet Ganov                }
189ae0e03a9e03de34e37b768b971d7596d7220a053Svet Ganov                mPendingWork.add(message);
190ae0e03a9e03de34e37b768b971d7596d7220a053Svet Ganov                scheduleNextMessageIfNeededLocked();
191ae0e03a9e03de34e37b768b971d7596d7220a053Svet Ganov            }
192ae0e03a9e03de34e37b768b971d7596d7220a053Svet Ganov        }
193ae0e03a9e03de34e37b768b971d7596d7220a053Svet Ganov
194ae0e03a9e03de34e37b768b971d7596d7220a053Svet Ganov        @Override
195ae0e03a9e03de34e37b768b971d7596d7220a053Svet Ganov        public void onServiceConnected(ComponentName name, IBinder service) {
196ae0e03a9e03de34e37b768b971d7596d7220a053Svet Ganov            synchronized (mLock) {
197ae0e03a9e03de34e37b768b971d7596d7220a053Svet Ganov                mRemoteInstance = IRuntimePermissionPresenter.Stub.asInterface(service);
198ae0e03a9e03de34e37b768b971d7596d7220a053Svet Ganov                scheduleNextMessageIfNeededLocked();
199ae0e03a9e03de34e37b768b971d7596d7220a053Svet Ganov            }
200ae0e03a9e03de34e37b768b971d7596d7220a053Svet Ganov        }
201ae0e03a9e03de34e37b768b971d7596d7220a053Svet Ganov
202ae0e03a9e03de34e37b768b971d7596d7220a053Svet Ganov        @Override
203ae0e03a9e03de34e37b768b971d7596d7220a053Svet Ganov        public void onServiceDisconnected(ComponentName name) {
204ae0e03a9e03de34e37b768b971d7596d7220a053Svet Ganov            synchronized (mLock) {
205ae0e03a9e03de34e37b768b971d7596d7220a053Svet Ganov                mRemoteInstance = null;
206ae0e03a9e03de34e37b768b971d7596d7220a053Svet Ganov            }
207ae0e03a9e03de34e37b768b971d7596d7220a053Svet Ganov        }
208ae0e03a9e03de34e37b768b971d7596d7220a053Svet Ganov
209ae0e03a9e03de34e37b768b971d7596d7220a053Svet Ganov        @Override
210ae0e03a9e03de34e37b768b971d7596d7220a053Svet Ganov        public void handleMessage(Message msg) {
211ae0e03a9e03de34e37b768b971d7596d7220a053Svet Ganov            switch (msg.what) {
212ae0e03a9e03de34e37b768b971d7596d7220a053Svet Ganov                case MSG_GET_APP_PERMISSIONS: {
213ae0e03a9e03de34e37b768b971d7596d7220a053Svet Ganov                    SomeArgs args = (SomeArgs) msg.obj;
214ae0e03a9e03de34e37b768b971d7596d7220a053Svet Ganov                    final String packageName = (String) args.arg1;
215ae0e03a9e03de34e37b768b971d7596d7220a053Svet Ganov                    final OnResultCallback callback = (OnResultCallback) args.arg2;
216ae0e03a9e03de34e37b768b971d7596d7220a053Svet Ganov                    final Handler handler = (Handler) args.arg3;
217ae0e03a9e03de34e37b768b971d7596d7220a053Svet Ganov                    args.recycle();
218ae0e03a9e03de34e37b768b971d7596d7220a053Svet Ganov                    final IRuntimePermissionPresenter remoteInstance;
219ae0e03a9e03de34e37b768b971d7596d7220a053Svet Ganov                    synchronized (mLock) {
220ae0e03a9e03de34e37b768b971d7596d7220a053Svet Ganov                        remoteInstance = mRemoteInstance;
221ae0e03a9e03de34e37b768b971d7596d7220a053Svet Ganov                    }
222ae0e03a9e03de34e37b768b971d7596d7220a053Svet Ganov                    if (remoteInstance == null) {
223ae0e03a9e03de34e37b768b971d7596d7220a053Svet Ganov                        return;
224ae0e03a9e03de34e37b768b971d7596d7220a053Svet Ganov                    }
225ae0e03a9e03de34e37b768b971d7596d7220a053Svet Ganov                    try {
226ae0e03a9e03de34e37b768b971d7596d7220a053Svet Ganov                        remoteInstance.getAppPermissions(packageName,
227ae0e03a9e03de34e37b768b971d7596d7220a053Svet Ganov                                new RemoteCallback(new RemoteCallback.OnResultListener() {
228ae0e03a9e03de34e37b768b971d7596d7220a053Svet Ganov                            @Override
229ae0e03a9e03de34e37b768b971d7596d7220a053Svet Ganov                            public void onResult(Bundle result) {
230ae0e03a9e03de34e37b768b971d7596d7220a053Svet Ganov                                final List<RuntimePermissionPresentationInfo> reportedPermissions;
231ae0e03a9e03de34e37b768b971d7596d7220a053Svet Ganov                                List<RuntimePermissionPresentationInfo> permissions = null;
232ae0e03a9e03de34e37b768b971d7596d7220a053Svet Ganov                                if (result != null) {
233ae0e03a9e03de34e37b768b971d7596d7220a053Svet Ganov                                    permissions = result.getParcelableArrayList(KEY_RESULT);
234ae0e03a9e03de34e37b768b971d7596d7220a053Svet Ganov                                }
235ae0e03a9e03de34e37b768b971d7596d7220a053Svet Ganov                                if (permissions == null) {
236ae0e03a9e03de34e37b768b971d7596d7220a053Svet Ganov                                    permissions = Collections.emptyList();
237ae0e03a9e03de34e37b768b971d7596d7220a053Svet Ganov                                }
238ae0e03a9e03de34e37b768b971d7596d7220a053Svet Ganov                                reportedPermissions = permissions;
239ae0e03a9e03de34e37b768b971d7596d7220a053Svet Ganov                                if (handler != null) {
240ae0e03a9e03de34e37b768b971d7596d7220a053Svet Ganov                                    handler.post(new Runnable() {
241ae0e03a9e03de34e37b768b971d7596d7220a053Svet Ganov                                        @Override
242ae0e03a9e03de34e37b768b971d7596d7220a053Svet Ganov                                        public void run() {
243ae0e03a9e03de34e37b768b971d7596d7220a053Svet Ganov                                            callback.onGetAppPermissions(reportedPermissions);
244ae0e03a9e03de34e37b768b971d7596d7220a053Svet Ganov                                        }
245ae0e03a9e03de34e37b768b971d7596d7220a053Svet Ganov                                    });
246ae0e03a9e03de34e37b768b971d7596d7220a053Svet Ganov                                } else {
247ae0e03a9e03de34e37b768b971d7596d7220a053Svet Ganov                                    callback.onGetAppPermissions(reportedPermissions);
248ae0e03a9e03de34e37b768b971d7596d7220a053Svet Ganov                                }
249ae0e03a9e03de34e37b768b971d7596d7220a053Svet Ganov                            }
250ae0e03a9e03de34e37b768b971d7596d7220a053Svet Ganov                        }, this));
251ae0e03a9e03de34e37b768b971d7596d7220a053Svet Ganov                    } catch (RemoteException re) {
252ae0e03a9e03de34e37b768b971d7596d7220a053Svet Ganov                        Log.e(TAG, "Error getting app permissions", re);
253ae0e03a9e03de34e37b768b971d7596d7220a053Svet Ganov                    }
254ae0e03a9e03de34e37b768b971d7596d7220a053Svet Ganov                    scheduleUnbind();
255ae0e03a9e03de34e37b768b971d7596d7220a053Svet Ganov                } break;
256ae0e03a9e03de34e37b768b971d7596d7220a053Svet Ganov
257ae0e03a9e03de34e37b768b971d7596d7220a053Svet Ganov                case MSG_GET_APPS_USING_PERMISSIONS: {
258ae0e03a9e03de34e37b768b971d7596d7220a053Svet Ganov                    SomeArgs args = (SomeArgs) msg.obj;
259ae0e03a9e03de34e37b768b971d7596d7220a053Svet Ganov                    final OnResultCallback callback = (OnResultCallback) args.arg1;
260ae0e03a9e03de34e37b768b971d7596d7220a053Svet Ganov                    final Handler handler = (Handler) args.arg2;
261ae0e03a9e03de34e37b768b971d7596d7220a053Svet Ganov                    final boolean system = args.argi1 == 1;
262ae0e03a9e03de34e37b768b971d7596d7220a053Svet Ganov                    args.recycle();
263ae0e03a9e03de34e37b768b971d7596d7220a053Svet Ganov                    final IRuntimePermissionPresenter remoteInstance;
264ae0e03a9e03de34e37b768b971d7596d7220a053Svet Ganov                    synchronized (mLock) {
265ae0e03a9e03de34e37b768b971d7596d7220a053Svet Ganov                        remoteInstance = mRemoteInstance;
266ae0e03a9e03de34e37b768b971d7596d7220a053Svet Ganov                    }
267ae0e03a9e03de34e37b768b971d7596d7220a053Svet Ganov                    if (remoteInstance == null) {
268ae0e03a9e03de34e37b768b971d7596d7220a053Svet Ganov                        return;
269ae0e03a9e03de34e37b768b971d7596d7220a053Svet Ganov                    }
270ae0e03a9e03de34e37b768b971d7596d7220a053Svet Ganov                    try {
271ae0e03a9e03de34e37b768b971d7596d7220a053Svet Ganov                        remoteInstance.getAppsUsingPermissions(system, new RemoteCallback(
272ae0e03a9e03de34e37b768b971d7596d7220a053Svet Ganov                                new RemoteCallback.OnResultListener() {
273ae0e03a9e03de34e37b768b971d7596d7220a053Svet Ganov                            @Override
274ae0e03a9e03de34e37b768b971d7596d7220a053Svet Ganov                            public void onResult(Bundle result) {
275ae0e03a9e03de34e37b768b971d7596d7220a053Svet Ganov                                final List<ApplicationInfo> reportedApps;
276ae0e03a9e03de34e37b768b971d7596d7220a053Svet Ganov                                List<ApplicationInfo> apps = null;
277ae0e03a9e03de34e37b768b971d7596d7220a053Svet Ganov                                if (result != null) {
278ae0e03a9e03de34e37b768b971d7596d7220a053Svet Ganov                                    apps = result.getParcelableArrayList(KEY_RESULT);
279ae0e03a9e03de34e37b768b971d7596d7220a053Svet Ganov                                }
280ae0e03a9e03de34e37b768b971d7596d7220a053Svet Ganov                                if (apps == null) {
281ae0e03a9e03de34e37b768b971d7596d7220a053Svet Ganov                                    apps = Collections.emptyList();
282ae0e03a9e03de34e37b768b971d7596d7220a053Svet Ganov                                }
283ae0e03a9e03de34e37b768b971d7596d7220a053Svet Ganov                                reportedApps = apps;
284ae0e03a9e03de34e37b768b971d7596d7220a053Svet Ganov                                if (handler != null) {
285ae0e03a9e03de34e37b768b971d7596d7220a053Svet Ganov                                    handler.post(new Runnable() {
286ae0e03a9e03de34e37b768b971d7596d7220a053Svet Ganov                                        @Override
287ae0e03a9e03de34e37b768b971d7596d7220a053Svet Ganov                                        public void run() {
288ae0e03a9e03de34e37b768b971d7596d7220a053Svet Ganov                                            callback.getAppsUsingPermissions(system, reportedApps);
289ae0e03a9e03de34e37b768b971d7596d7220a053Svet Ganov                                        }
290ae0e03a9e03de34e37b768b971d7596d7220a053Svet Ganov                                    });
291ae0e03a9e03de34e37b768b971d7596d7220a053Svet Ganov                                } else {
292ae0e03a9e03de34e37b768b971d7596d7220a053Svet Ganov                                    callback.getAppsUsingPermissions(system, reportedApps);
293ae0e03a9e03de34e37b768b971d7596d7220a053Svet Ganov                                }
294ae0e03a9e03de34e37b768b971d7596d7220a053Svet Ganov                            }
295ae0e03a9e03de34e37b768b971d7596d7220a053Svet Ganov                        }, this));
296ae0e03a9e03de34e37b768b971d7596d7220a053Svet Ganov                    } catch (RemoteException re) {
297ae0e03a9e03de34e37b768b971d7596d7220a053Svet Ganov                        Log.e(TAG, "Error getting apps using permissions", re);
298ae0e03a9e03de34e37b768b971d7596d7220a053Svet Ganov                    }
299ae0e03a9e03de34e37b768b971d7596d7220a053Svet Ganov                    scheduleUnbind();
300ae0e03a9e03de34e37b768b971d7596d7220a053Svet Ganov                } break;
301ae0e03a9e03de34e37b768b971d7596d7220a053Svet Ganov
302ae0e03a9e03de34e37b768b971d7596d7220a053Svet Ganov                case MSG_UNBIND: {
303ae0e03a9e03de34e37b768b971d7596d7220a053Svet Ganov                    synchronized (mLock) {
304ae0e03a9e03de34e37b768b971d7596d7220a053Svet Ganov                        if (mBound) {
305ae0e03a9e03de34e37b768b971d7596d7220a053Svet Ganov                            mContext.unbindService(this);
306ae0e03a9e03de34e37b768b971d7596d7220a053Svet Ganov                            mBound = false;
307ae0e03a9e03de34e37b768b971d7596d7220a053Svet Ganov                        }
308ae0e03a9e03de34e37b768b971d7596d7220a053Svet Ganov                        mRemoteInstance = null;
309ae0e03a9e03de34e37b768b971d7596d7220a053Svet Ganov                    }
310ae0e03a9e03de34e37b768b971d7596d7220a053Svet Ganov                } break;
311ae0e03a9e03de34e37b768b971d7596d7220a053Svet Ganov            }
312ae0e03a9e03de34e37b768b971d7596d7220a053Svet Ganov
313ae0e03a9e03de34e37b768b971d7596d7220a053Svet Ganov            synchronized (mLock) {
314ae0e03a9e03de34e37b768b971d7596d7220a053Svet Ganov                scheduleNextMessageIfNeededLocked();
315ae0e03a9e03de34e37b768b971d7596d7220a053Svet Ganov            }
316ae0e03a9e03de34e37b768b971d7596d7220a053Svet Ganov        }
317ae0e03a9e03de34e37b768b971d7596d7220a053Svet Ganov
318ae0e03a9e03de34e37b768b971d7596d7220a053Svet Ganov        private void scheduleNextMessageIfNeededLocked() {
319ae0e03a9e03de34e37b768b971d7596d7220a053Svet Ganov            if (mBound && mRemoteInstance != null && !mPendingWork.isEmpty()) {
320ae0e03a9e03de34e37b768b971d7596d7220a053Svet Ganov                Message nextMessage = mPendingWork.remove(0);
321ae0e03a9e03de34e37b768b971d7596d7220a053Svet Ganov                sendMessage(nextMessage);
322ae0e03a9e03de34e37b768b971d7596d7220a053Svet Ganov            }
323ae0e03a9e03de34e37b768b971d7596d7220a053Svet Ganov        }
324ae0e03a9e03de34e37b768b971d7596d7220a053Svet Ganov
325ae0e03a9e03de34e37b768b971d7596d7220a053Svet Ganov        private void scheduleUnbind() {
326ae0e03a9e03de34e37b768b971d7596d7220a053Svet Ganov            removeMessages(MSG_UNBIND);
327ae0e03a9e03de34e37b768b971d7596d7220a053Svet Ganov            sendEmptyMessageDelayed(MSG_UNBIND, UNBIND_TIMEOUT_MILLIS);
328ae0e03a9e03de34e37b768b971d7596d7220a053Svet Ganov        }
329ae0e03a9e03de34e37b768b971d7596d7220a053Svet Ganov    }
330ae0e03a9e03de34e37b768b971d7596d7220a053Svet Ganov}
331