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