• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2021 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 
33 import androidx.annotation.VisibleForTesting;
34 
35 import com.android.car.settings.R;
36 import com.android.car.settings.common.ConfirmationDialogFragment;
37 import com.android.car.settings.common.FragmentController;
38 import com.android.car.settings.common.PowerPolicyListener;
39 import com.android.car.settings.common.PreferenceController;
40 import com.android.car.settings.enterprise.EnterpriseUtils;
41 import com.android.car.ui.preference.CarUiTwoActionSwitchPreference;
42 
43 /**
44  * Enables/disables ADAS (Advanced Driver-assistance systems) GNSS bypass via SwitchPreference.
45  */
46 public class AdasLocationSwitchPreferenceController extends
47         PreferenceController<CarUiTwoActionSwitchPreference> {
48     private final Context mContext;
49     private final LocationManager mLocationManager;
50 
51     private final BroadcastReceiver mAdasReceiver = new BroadcastReceiver() {
52         @Override
53         public void onReceive(Context context, Intent intent) {
54             refreshUi();
55         }
56     };
57 
58     private final BroadcastReceiver mLocationReceiver = new BroadcastReceiver() {
59         @Override
60         public void onReceive(Context context, Intent intent) {
61             // Turns Driver assistance on when main location switch is on. Location service don't
62             // support the case where main location switch on and Driver assistance off
63             if (mLocationManager.isLocationEnabled()) {
64                 mLocationManager.setAdasGnssLocationEnabled(true);
65             }
66             refreshUi();
67         }
68     };
69 
70     private static final IntentFilter INTENT_FILTER_ADAS_GNSS_ENABLED_CHANGED = new IntentFilter(
71             LocationManager.ACTION_ADAS_GNSS_ENABLED_CHANGED);
72 
73     private static final IntentFilter INTENT_FILTER_LOCATION_MODE_CHANGED = new IntentFilter(
74             LocationManager.MODE_CHANGED_ACTION);
75     @VisibleForTesting
76     final PowerPolicyListener mPowerPolicyListener;
77 
AdasLocationSwitchPreferenceController(Context context, String preferenceKey, FragmentController fragmentController, CarUxRestrictions uxRestrictions)78     public AdasLocationSwitchPreferenceController(Context context, String preferenceKey,
79             FragmentController fragmentController, CarUxRestrictions uxRestrictions) {
80         super(context, preferenceKey, fragmentController, uxRestrictions);
81         mContext = context;
82         mLocationManager = context.getSystemService(LocationManager.class);
83         mPowerPolicyListener = new PowerPolicyListener(context, LOCATION,
84                 isOn -> {
85                     handlePowerPolicyChange(getPreference(), isOn);
86                 });
87     }
88 
89     @Override
getPreferenceType()90     protected Class<CarUiTwoActionSwitchPreference> getPreferenceType() {
91         return CarUiTwoActionSwitchPreference.class;
92     }
93 
94     @Override
getAvailabilityStatus()95     protected int getAvailabilityStatus() {
96         if (hasUserRestrictionByDpm(getContext(), DISALLOW_CONFIG_LOCATION)
97                 || hasUserRestrictionByDpm(getContext(), DISALLOW_SHARE_LOCATION)) {
98             return AVAILABLE_FOR_VIEWING;
99         }
100         return AVAILABLE;
101     }
102 
103     @Override
updateState(CarUiTwoActionSwitchPreference preference)104     protected void updateState(CarUiTwoActionSwitchPreference preference) {
105         updateSwitchPreference(preference, mLocationManager.isAdasGnssLocationEnabled());
106     }
107 
108     @Override
onCreateInternal()109     protected void onCreateInternal() {
110         getPreference().setOnSecondaryActionClickListener(isChecked -> {
111             if (!isChecked) {
112                 getFragmentController().showDialog(getConfirmationDialog(),
113                         ConfirmationDialogFragment.TAG);
114                 refreshUi();
115             } else {
116                 mLocationManager.setAdasGnssLocationEnabled(true);
117             }
118         });
119         setClickableWhileDisabled(getPreference(), /* clickable= */ true, p -> {
120             if (hasUserRestrictionByDpm(getContext(), DISALLOW_SHARE_LOCATION)) {
121                 showActionDisabledByAdminDialog(DISALLOW_SHARE_LOCATION);
122                 return;
123             }
124             if (hasUserRestrictionByDpm(getContext(), DISALLOW_CONFIG_LOCATION)) {
125                 showActionDisabledByAdminDialog(DISALLOW_CONFIG_LOCATION);
126                 return;
127             }
128         });
129     }
130 
131     @Override
onStartInternal()132     protected void onStartInternal() {
133         mContext.registerReceiver(mAdasReceiver, INTENT_FILTER_ADAS_GNSS_ENABLED_CHANGED,
134                 Context.RECEIVER_NOT_EXPORTED);
135         mContext.registerReceiver(mLocationReceiver, INTENT_FILTER_LOCATION_MODE_CHANGED,
136                 Context.RECEIVER_NOT_EXPORTED);
137     }
138 
139     @Override
onResumeInternal()140     protected void onResumeInternal() {
141         mPowerPolicyListener.handleCurrentPolicy();
142     }
143 
144     @Override
onStopInternal()145     protected void onStopInternal() {
146         mContext.unregisterReceiver(mAdasReceiver);
147         mContext.unregisterReceiver(mLocationReceiver);
148     }
149 
150     @Override
onDestroyInternal()151     protected void onDestroyInternal() {
152         mPowerPolicyListener.release();
153     }
154 
updateSwitchPreference(CarUiTwoActionSwitchPreference preference, boolean enabled)155     private void updateSwitchPreference(CarUiTwoActionSwitchPreference preference,
156             boolean enabled) {
157         if (enabled && hasUserRestrictionByDpm(getContext(), DISALLOW_SHARE_LOCATION)) {
158             preference.setSecondaryActionChecked(false);
159             preference.setSecondaryActionEnabled(false);
160         } else {
161             preference.setSecondaryActionChecked(enabled);
162             preference.setSecondaryActionEnabled(!mLocationManager.isLocationEnabled());
163         }
164     }
165 
handlePowerPolicyChange(CarUiTwoActionSwitchPreference preference, boolean enabled)166     private void handlePowerPolicyChange(CarUiTwoActionSwitchPreference preference,
167             boolean enabled) {
168         if (hasUserRestrictionByDpm(getContext(), DISALLOW_CONFIG_LOCATION)
169                 || hasUserRestrictionByDpm(getContext(), DISALLOW_SHARE_LOCATION)
170                 ||  mLocationManager.isLocationEnabled()) {
171             preference.setSecondaryActionEnabled(false);
172             return;
173         }
174         preference.setSecondaryActionEnabled(enabled);
175     }
176 
177     /**
178      * Assigns confirm action as negative button listener and cancel action as positive button
179      * listener, because the UX design requires the cancel button has to be on right and the confirm
180      * button on left.
181      */
getConfirmationDialog()182     private ConfirmationDialogFragment getConfirmationDialog() {
183         return new ConfirmationDialogFragment.Builder(getContext())
184                 .setMessage(mContext
185                         .getString(R.string.location_driver_assistance_toggle_off_warning))
186                 .setNegativeButton(mContext
187                         .getString(R.string.driver_assistance_warning_confirm_label), arguments -> {
188                                 mLocationManager.setAdasGnssLocationEnabled(false);
189                         })
190                 .setPositiveButton(android.R.string.cancel,
191                         /* rejectListener= */ null)
192                 .build();
193     }
194 
showActionDisabledByAdminDialog(String restrictionType)195     private void showActionDisabledByAdminDialog(String restrictionType) {
196         getFragmentController().showDialog(
197                 EnterpriseUtils.getActionDisabledByAdminDialog(getContext(),
198                         restrictionType),
199                 DISABLED_BY_ADMIN_CONFIRM_DIALOG_TAG);
200     }
201 }
202