1 /* 2 * Copyright (C) 2019 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.display; 18 19 import static android.hardware.SensorPrivacyManager.Sensors.CAMERA; 20 21 import static com.android.settings.core.BasePreferenceController.AVAILABLE_UNSEARCHABLE; 22 import static com.android.settings.core.BasePreferenceController.UNSUPPORTED_ON_DEVICE; 23 24 import android.Manifest; 25 import android.app.settings.SettingsEnums; 26 import android.content.Context; 27 import android.content.Intent; 28 import android.content.pm.PackageManager; 29 import android.content.pm.ResolveInfo; 30 import android.hardware.SensorPrivacyManager; 31 import android.os.PowerManager; 32 import android.os.UserManager; 33 import android.provider.Settings; 34 import android.service.attention.AttentionService; 35 import android.text.TextUtils; 36 37 import androidx.preference.PreferenceScreen; 38 39 import com.android.settings.R; 40 import com.android.settings.bluetooth.RestrictionUtils; 41 import com.android.settings.overlay.FeatureFactory; 42 import com.android.settingslib.RestrictedLockUtils.EnforcedAdmin; 43 import com.android.settingslib.RestrictedSwitchPreference; 44 import com.android.settingslib.core.instrumentation.MetricsFeatureProvider; 45 46 import com.google.common.annotations.VisibleForTesting; 47 48 /** The controller for Screen attention switch preference. */ 49 public class AdaptiveSleepPreferenceController { 50 public static final String PREFERENCE_KEY = "adaptive_sleep"; 51 private static final int DEFAULT_VALUE = 0; 52 private final SensorPrivacyManager mPrivacyManager; 53 private final RestrictionUtils mRestrictionUtils; 54 private final PackageManager mPackageManager; 55 private final Context mContext; 56 private final MetricsFeatureProvider mMetricsFeatureProvider; 57 private final PowerManager mPowerManager; 58 59 @VisibleForTesting 60 RestrictedSwitchPreference mPreference; 61 AdaptiveSleepPreferenceController(Context context, RestrictionUtils restrictionUtils)62 public AdaptiveSleepPreferenceController(Context context, RestrictionUtils restrictionUtils) { 63 mContext = context; 64 mRestrictionUtils = restrictionUtils; 65 mMetricsFeatureProvider = FeatureFactory.getFactory(context).getMetricsFeatureProvider(); 66 mPrivacyManager = SensorPrivacyManager.getInstance(context); 67 mPowerManager = context.getSystemService(PowerManager.class); 68 mPackageManager = context.getPackageManager(); 69 } 70 AdaptiveSleepPreferenceController(Context context)71 public AdaptiveSleepPreferenceController(Context context) { 72 this(context, new RestrictionUtils()); 73 } 74 75 /** 76 * Adds the controlled preference to the provided preference screen. 77 */ addToScreen(PreferenceScreen screen)78 public void addToScreen(PreferenceScreen screen) { 79 updatePreference(); 80 screen.addPreference(mPreference); 81 } 82 83 /** 84 * Updates the appearance of the preference. 85 */ updatePreference()86 public void updatePreference() { 87 initializePreference(); 88 final EnforcedAdmin enforcedAdmin = mRestrictionUtils.checkIfRestrictionEnforced(mContext, 89 UserManager.DISALLOW_CONFIG_SCREEN_TIMEOUT); 90 if (enforcedAdmin != null) { 91 mPreference.setDisabledByAdmin(enforcedAdmin); 92 } else { 93 mPreference.setChecked(isChecked()); 94 mPreference.setEnabled(hasSufficientPermission(mPackageManager) && !isCameraLocked() 95 && !isPowerSaveMode()); 96 } 97 } 98 99 @VisibleForTesting initializePreference()100 void initializePreference() { 101 if (mPreference == null) { 102 mPreference = new RestrictedSwitchPreference(mContext); 103 mPreference.setTitle(R.string.adaptive_sleep_title); 104 mPreference.setSummary(R.string.adaptive_sleep_description); 105 mPreference.setChecked(isChecked()); 106 mPreference.setKey(PREFERENCE_KEY); 107 mPreference.setOnPreferenceClickListener(preference -> { 108 final boolean isChecked = ((RestrictedSwitchPreference) preference).isChecked(); 109 mMetricsFeatureProvider.action(mContext, 110 SettingsEnums.ACTION_SCREEN_ATTENTION_CHANGED, 111 isChecked); 112 Settings.Secure.putInt(mContext.getContentResolver(), 113 Settings.Secure.ADAPTIVE_SLEEP, isChecked ? 1 : DEFAULT_VALUE); 114 return true; 115 }); 116 } 117 } 118 119 @VisibleForTesting isChecked()120 boolean isChecked() { 121 return hasSufficientPermission(mContext.getPackageManager()) && !isCameraLocked() 122 && !isPowerSaveMode() && Settings.Secure.getInt(mContext.getContentResolver(), 123 Settings.Secure.ADAPTIVE_SLEEP, DEFAULT_VALUE) 124 != DEFAULT_VALUE; 125 } 126 127 /** 128 * Need this because all controller tests use RoboElectric. No easy way to mock this service, 129 * so we mock the call we need 130 */ 131 @VisibleForTesting isCameraLocked()132 boolean isCameraLocked() { 133 return mPrivacyManager.isSensorPrivacyEnabled(CAMERA); 134 } 135 136 @VisibleForTesting isPowerSaveMode()137 boolean isPowerSaveMode() { 138 return mPowerManager.isPowerSaveMode(); 139 } 140 isControllerAvailable(Context context)141 public static int isControllerAvailable(Context context) { 142 return isAdaptiveSleepSupported(context) 143 ? AVAILABLE_UNSEARCHABLE 144 : UNSUPPORTED_ON_DEVICE; 145 } 146 isAdaptiveSleepSupported(Context context)147 static boolean isAdaptiveSleepSupported(Context context) { 148 return context.getResources().getBoolean( 149 com.android.internal.R.bool.config_adaptive_sleep_available) 150 && isAttentionServiceAvailable(context); 151 } 152 isAttentionServiceAvailable(Context context)153 private static boolean isAttentionServiceAvailable(Context context) { 154 final PackageManager packageManager = context.getPackageManager(); 155 final String resolvePackage = packageManager.getAttentionServicePackageName(); 156 if (TextUtils.isEmpty(resolvePackage)) { 157 return false; 158 } 159 final Intent intent = new Intent(AttentionService.SERVICE_INTERFACE).setPackage( 160 resolvePackage); 161 final ResolveInfo resolveInfo = packageManager.resolveService(intent, 162 PackageManager.MATCH_SYSTEM_ONLY); 163 return resolveInfo != null && resolveInfo.serviceInfo != null; 164 } 165 hasSufficientPermission(PackageManager packageManager)166 static boolean hasSufficientPermission(PackageManager packageManager) { 167 final String attentionPackage = packageManager.getAttentionServicePackageName(); 168 return attentionPackage != null && packageManager.checkPermission( 169 Manifest.permission.CAMERA, attentionPackage) == PackageManager.PERMISSION_GRANTED; 170 } 171 } 172