• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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