1 /* 2 * Copyright (C) 2023 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.devicelockcontroller; 18 19 import android.annotation.CallbackExecutor; 20 import android.annotation.RequiresPermission; 21 import android.content.Context; 22 import android.devicelock.DeviceLockManager; 23 import android.devicelock.IDeviceLockService; 24 import android.os.Handler; 25 import android.os.Looper; 26 import android.os.OutcomeReceiver; 27 import android.os.RemoteCallback; 28 import android.os.RemoteException; 29 30 import androidx.annotation.NonNull; 31 32 import java.util.Objects; 33 import java.util.concurrent.Executor; 34 35 /** 36 * Implementation for SystemDeviceLockManager. 37 */ 38 public final class SystemDeviceLockManagerImpl implements SystemDeviceLockManager { 39 private static final String TAG = "SystemDeviceLockManagerImpl"; 40 41 private final IDeviceLockService mIDeviceLockService; 42 43 private static final String MANAGE_DEVICE_LOCK_SERVICE_FROM_CONTROLLER = 44 "com.android.devicelockcontroller.permission." 45 + "MANAGE_DEVICE_LOCK_SERVICE_FROM_CONTROLLER"; 46 SystemDeviceLockManagerImpl(Context context)47 private SystemDeviceLockManagerImpl(Context context) { 48 final DeviceLockManager deviceLockManager = 49 context.getSystemService(DeviceLockManager.class); 50 51 mIDeviceLockService = deviceLockManager.getService(); 52 } 53 SystemDeviceLockManagerImpl()54 private SystemDeviceLockManagerImpl() { 55 this(DeviceLockControllerApplication.getAppContext()); 56 } 57 58 // Initialization-on-demand holder. 59 private static final class SystemDeviceLockManagerHolder { 60 static final SystemDeviceLockManagerImpl sSystemDeviceLockManager = 61 new SystemDeviceLockManagerImpl(); 62 } 63 64 /** 65 * Returns the lazily initialized singleton instance of the SystemDeviceLockManager. 66 */ getInstance()67 public static SystemDeviceLockManager getInstance() { 68 return SystemDeviceLockManagerHolder.sSystemDeviceLockManager; 69 } 70 71 @Override 72 @RequiresPermission(MANAGE_DEVICE_LOCK_SERVICE_FROM_CONTROLLER) addFinancedDeviceKioskRole(@onNull String packageName, @CallbackExecutor Executor executor, @NonNull OutcomeReceiver<Void, Exception> callback)73 public void addFinancedDeviceKioskRole(@NonNull String packageName, 74 @CallbackExecutor Executor executor, 75 @NonNull OutcomeReceiver<Void, Exception> callback) { 76 Objects.requireNonNull(executor); 77 Objects.requireNonNull(callback); 78 79 try { 80 mIDeviceLockService.addFinancedDeviceKioskRole(packageName, 81 new RemoteCallback(result -> executor.execute(() -> { 82 final boolean roleAdded = result.getBoolean( 83 IDeviceLockService.KEY_REMOTE_CALLBACK_RESULT); 84 if (roleAdded) { 85 callback.onResult(null /* result */); 86 } else { 87 callback.onError(new Exception("Failed to add financed role to: " 88 + packageName)); 89 } 90 }), new Handler(Looper.getMainLooper()))); 91 } catch (RemoteException e) { 92 executor.execute(() -> callback.onError(new RuntimeException(e))); 93 } 94 } 95 96 @Override 97 @RequiresPermission(MANAGE_DEVICE_LOCK_SERVICE_FROM_CONTROLLER) removeFinancedDeviceKioskRole(@onNull String packageName, @CallbackExecutor Executor executor, @NonNull OutcomeReceiver<Void, Exception> callback)98 public void removeFinancedDeviceKioskRole(@NonNull String packageName, 99 @CallbackExecutor Executor executor, 100 @NonNull OutcomeReceiver<Void, Exception> callback) { 101 Objects.requireNonNull(executor); 102 Objects.requireNonNull(callback); 103 104 try { 105 mIDeviceLockService.removeFinancedDeviceKioskRole(packageName, 106 new RemoteCallback(result -> executor.execute(() -> { 107 final boolean roleRemoved = result.getBoolean( 108 IDeviceLockService.KEY_REMOTE_CALLBACK_RESULT); 109 if (roleRemoved) { 110 callback.onResult(null /* result */); 111 } else { 112 callback.onError(new Exception("Failed to remove financed role from: " 113 + packageName)); 114 } 115 }), new Handler(Looper.getMainLooper()))); 116 } catch (RemoteException e) { 117 executor.execute(() -> callback.onError(new RuntimeException(e))); 118 } 119 } 120 121 @Override 122 @RequiresPermission(MANAGE_DEVICE_LOCK_SERVICE_FROM_CONTROLLER) setExemptFromActivityBackgroundStartRestriction(boolean exempt, @CallbackExecutor Executor executor, @NonNull OutcomeReceiver<Void, Exception> callback)123 public void setExemptFromActivityBackgroundStartRestriction(boolean exempt, 124 @CallbackExecutor Executor executor, 125 @NonNull OutcomeReceiver<Void, Exception> callback) { 126 Objects.requireNonNull(executor); 127 Objects.requireNonNull(callback); 128 129 try { 130 mIDeviceLockService.setExemptFromActivityBackgroundStartRestriction(exempt, 131 new RemoteCallback(result -> executor.execute(() -> { 132 final boolean restrictionChanged = result.getBoolean( 133 IDeviceLockService.KEY_REMOTE_CALLBACK_RESULT); 134 if (restrictionChanged) { 135 callback.onResult(null /* result */); 136 } else { 137 callback.onError(new Exception("Failed to change exempt from " 138 + "activity background start to: " 139 + (exempt ? "exempt" : "non exempt"))); 140 } 141 }), new Handler(Looper.getMainLooper()))); 142 } catch (RemoteException e) { 143 executor.execute(() -> callback.onError(new RuntimeException(e))); 144 } 145 } 146 147 @Override 148 @RequiresPermission(MANAGE_DEVICE_LOCK_SERVICE_FROM_CONTROLLER) setExemptFromHibernation(String packageName, boolean exempt, @CallbackExecutor Executor executor, @NonNull OutcomeReceiver<Void, Exception> callback)149 public void setExemptFromHibernation(String packageName, boolean exempt, 150 @CallbackExecutor Executor executor, 151 @NonNull OutcomeReceiver<Void, Exception> callback) { 152 Objects.requireNonNull(packageName); 153 Objects.requireNonNull(executor); 154 Objects.requireNonNull(callback); 155 156 try { 157 mIDeviceLockService.setExemptFromHibernation(packageName, exempt, 158 new RemoteCallback(result -> executor.execute(() -> { 159 final boolean restrictionChanged = result.getBoolean( 160 IDeviceLockService.KEY_REMOTE_CALLBACK_RESULT); 161 if (restrictionChanged) { 162 callback.onResult(null /* result */); 163 } else { 164 callback.onError(new Exception("Failed to change exempt from " 165 + "hibernation to: " 166 + (exempt ? "exempt" : "non exempt") + " for package: " 167 + packageName)); 168 } 169 }), new Handler(Looper.getMainLooper()))); 170 } catch (RemoteException e) { 171 executor.execute(() -> callback.onError(new RuntimeException(e))); 172 } 173 } 174 } 175