1 /* 2 * Copyright (C) 2020 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.car.settings.location; 18 19 import static android.car.hardware.power.PowerComponent.LOCATION; 20 import static android.os.UserManager.DISALLOW_CONFIG_LOCATION; 21 import static android.os.UserManager.DISALLOW_SHARE_LOCATION; 22 23 import static com.android.car.settings.enterprise.ActionDisabledByAdminDialogFragment.DISABLED_BY_ADMIN_CONFIRM_DIALOG_TAG; 24 import static com.android.car.settings.enterprise.EnterpriseUtils.hasUserRestrictionByDpm; 25 26 import android.car.drivingstate.CarUxRestrictions; 27 import android.content.BroadcastReceiver; 28 import android.content.Context; 29 import android.content.Intent; 30 import android.content.IntentFilter; 31 import android.location.LocationManager; 32 import android.os.UserHandle; 33 import android.provider.Settings; 34 import android.widget.Toast; 35 36 import androidx.annotation.VisibleForTesting; 37 38 import com.android.car.settings.R; 39 import com.android.car.settings.common.ColoredSwitchPreference; 40 import com.android.car.settings.common.FragmentController; 41 import com.android.car.settings.common.Logger; 42 import com.android.car.settings.common.PowerPolicyListener; 43 import com.android.car.settings.common.PreferenceController; 44 import com.android.car.settings.enterprise.EnterpriseUtils; 45 import com.android.settingslib.Utils; 46 47 /** 48 * Enables/disables location state via SwitchPreference. 49 */ 50 public class LocationStateSwitchPreferenceController extends 51 PreferenceController<ColoredSwitchPreference> { 52 private static final Logger LOG = new Logger( 53 LocationStateSwitchPreferenceController.class); 54 private static final IntentFilter INTENT_FILTER_LOCATION_MODE_CHANGED = 55 new IntentFilter(LocationManager.MODE_CHANGED_ACTION); 56 57 private boolean mIsPowerPolicyOn = true; 58 59 protected final LocationManager mLocationManager; 60 private final BroadcastReceiver mReceiver = new BroadcastReceiver() { 61 @Override 62 public void onReceive(Context context, Intent intent) { 63 refreshUi(); 64 } 65 }; 66 67 @VisibleForTesting 68 final PowerPolicyListener mPowerPolicyListener; 69 LocationStateSwitchPreferenceController(Context context, String preferenceKey, FragmentController fragmentController, CarUxRestrictions uxRestrictions)70 public LocationStateSwitchPreferenceController(Context context, 71 String preferenceKey, 72 FragmentController fragmentController, 73 CarUxRestrictions uxRestrictions) { 74 super(context, preferenceKey, fragmentController, uxRestrictions); 75 mLocationManager = context.getSystemService(LocationManager.class); 76 mPowerPolicyListener = new PowerPolicyListener(context, LOCATION, 77 isOn -> { 78 LOG.d("setting mIsPowerPolicyOn to " + isOn); 79 mIsPowerPolicyOn = isOn; 80 // mIsPowerPolicyOn is used in deciding the availability status. 81 // Call refreshUi() so that the UI can be updated as per 82 // getAvailabilityStatus(). 83 refreshUi(); 84 }); 85 } 86 87 @Override getDefaultAvailabilityStatus()88 protected int getDefaultAvailabilityStatus() { 89 if (hasUserRestrictionByDpm(getContext(), DISALLOW_CONFIG_LOCATION) 90 || hasUserRestrictionByDpm(getContext(), DISALLOW_SHARE_LOCATION) 91 || !mIsPowerPolicyOn) { 92 return AVAILABLE_FOR_VIEWING; 93 } 94 return AVAILABLE; 95 } 96 97 @Override getPreferenceType()98 protected Class<ColoredSwitchPreference> getPreferenceType() { 99 return ColoredSwitchPreference.class; 100 } 101 102 @Override updateState(ColoredSwitchPreference preference)103 protected void updateState(ColoredSwitchPreference preference) { 104 updateSwitchPreference(preference, mLocationManager.isLocationEnabled()); 105 } 106 107 @Override handlePreferenceChanged(ColoredSwitchPreference preference, Object newValue)108 protected boolean handlePreferenceChanged(ColoredSwitchPreference preference, 109 Object newValue) { 110 boolean isLocationEnabled = (Boolean) newValue; 111 Utils.updateLocationEnabled( 112 getContext(), 113 isLocationEnabled, 114 UserHandle.myUserId(), 115 Settings.Secure.LOCATION_CHANGER_SYSTEM_SETTINGS); 116 return true; 117 } 118 119 @Override onCreateInternal()120 protected void onCreateInternal() { 121 getPreference().setContentDescription( 122 getContext().getString(R.string.location_state_switch_content_description)); 123 setClickableWhileDisabled(getPreference(), /* clickable= */ true, p -> { 124 // All the cases here should coincide with the ones in getAvailabilityStatus() 125 if (!mIsPowerPolicyOn) { 126 Toast.makeText(getContext(), R.string.power_component_disabled, Toast.LENGTH_LONG) 127 .show(); 128 return; 129 } 130 if (hasUserRestrictionByDpm(getContext(), DISALLOW_SHARE_LOCATION)) { 131 showActionDisabledByAdminDialog(DISALLOW_SHARE_LOCATION); 132 return; 133 } 134 if (hasUserRestrictionByDpm(getContext(), DISALLOW_CONFIG_LOCATION)) { 135 showActionDisabledByAdminDialog(DISALLOW_CONFIG_LOCATION); 136 return; 137 } 138 }); 139 } 140 141 @Override onStartInternal()142 protected void onStartInternal() { 143 getContext().registerReceiver(mReceiver, INTENT_FILTER_LOCATION_MODE_CHANGED); 144 } 145 146 @Override onResumeInternal()147 protected void onResumeInternal() { 148 mPowerPolicyListener.handleCurrentPolicy(); 149 } 150 151 @Override onStopInternal()152 protected void onStopInternal() { 153 getContext().unregisterReceiver(mReceiver); 154 } 155 156 @Override onDestroyInternal()157 protected void onDestroyInternal() { 158 mPowerPolicyListener.release(); 159 } 160 updateSwitchPreference(ColoredSwitchPreference preference, boolean enabled)161 private void updateSwitchPreference(ColoredSwitchPreference preference, 162 boolean enabled) { 163 preference.setChecked(enabled 164 && !hasUserRestrictionByDpm(getContext(), DISALLOW_SHARE_LOCATION)); 165 } 166 showActionDisabledByAdminDialog(String restrictionType)167 private void showActionDisabledByAdminDialog(String restrictionType) { 168 getFragmentController().showDialog( 169 EnterpriseUtils.getActionDisabledByAdminDialog(getContext(), 170 restrictionType), 171 DISABLED_BY_ADMIN_CONFIRM_DIALOG_TAG); 172 } 173 } 174