1 /*
2  * Copyright 2018 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.bluetooth;
18 
19 import static android.os.UserManager.DISALLOW_BLUETOOTH;
20 import static android.os.UserManager.DISALLOW_CONFIG_BLUETOOTH;
21 
22 import static com.android.car.settings.enterprise.ActionDisabledByAdminDialogFragment.DISABLED_BY_ADMIN_CONFIRM_DIALOG_TAG;
23 import static com.android.car.settings.enterprise.EnterpriseUtils.hasUserRestrictionByDpm;
24 
25 import android.bluetooth.BluetoothAdapter;
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.content.pm.PackageManager;
32 import android.os.UserManager;
33 
34 import androidx.lifecycle.LifecycleObserver;
35 import androidx.preference.Preference;
36 
37 import com.android.car.settings.R;
38 import com.android.car.settings.common.FragmentController;
39 import com.android.car.settings.common.PreferenceController;
40 import com.android.car.settings.enterprise.EnterpriseUtils;
41 
42 /**
43  * Controls a preference that, when clicked, launches the page for pairing new Bluetooth devices.
44  * The associated preference for this controller should define the fragment attribute or an intent
45  * to launch for the Bluetooth device pairing page. If the adapter is not enabled, a click will
46  * enable Bluetooth. The summary message is updated to indicate this effect to the user.
47  */
48 public class PairNewDevicePreferenceController extends PreferenceController<Preference> implements
49         LifecycleObserver {
50 
51     private final IntentFilter mIntentFilter = new IntentFilter(
52             BluetoothAdapter.ACTION_STATE_CHANGED);
53     private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
54         @Override
55         public void onReceive(Context context, Intent intent) {
56             refreshUi();
57         }
58     };
59     private final UserManager mUserManager;
60 
PairNewDevicePreferenceController(Context context, String preferenceKey, FragmentController fragmentController, CarUxRestrictions uxRestrictions)61     public PairNewDevicePreferenceController(Context context, String preferenceKey,
62             FragmentController fragmentController, CarUxRestrictions uxRestrictions) {
63         super(context, preferenceKey, fragmentController, uxRestrictions);
64         mUserManager = UserManager.get(context);
65     }
66 
67     @Override
getPreferenceType()68     protected Class<Preference> getPreferenceType() {
69         return Preference.class;
70     }
71 
72     @Override
onCreateInternal()73     protected void onCreateInternal() {
74         super.onCreateInternal();
75         setClickableWhileDisabled(getPreference(), /* clickable= */ true, p -> {
76             if (getAvailabilityStatus() == AVAILABLE_FOR_VIEWING) {
77                 showActionDisabledByAdminDialog();
78             }
79         });
80     }
81 
showActionDisabledByAdminDialog()82     private void showActionDisabledByAdminDialog() {
83         getFragmentController().showDialog(
84                 EnterpriseUtils.getActionDisabledByAdminDialog(getContext(),
85                         DISALLOW_CONFIG_BLUETOOTH),
86                 DISABLED_BY_ADMIN_CONFIRM_DIALOG_TAG);
87     }
88 
89     @Override
checkInitialized()90     protected void checkInitialized() {
91         if (getPreference().getIntent() == null && getPreference().getFragment() == null) {
92             throw new IllegalStateException(
93                     "Preference should declare fragment or intent for page to pair new devices");
94         }
95     }
96 
97     @Override
getAvailabilityStatus()98     protected int getAvailabilityStatus() {
99         if (!getContext().getPackageManager().hasSystemFeature(PackageManager.FEATURE_BLUETOOTH)) {
100             return UNSUPPORTED_ON_DEVICE;
101         }
102         if (hasUserRestrictionByDpm(getContext(), DISALLOW_CONFIG_BLUETOOTH)) {
103             return AVAILABLE_FOR_VIEWING;
104         }
105         return isUserRestricted() ? DISABLED_FOR_PROFILE : AVAILABLE;
106     }
107 
isUserRestricted()108     private boolean isUserRestricted() {
109         return mUserManager.hasUserRestriction(DISALLOW_BLUETOOTH)
110                 || mUserManager.hasUserRestriction(DISALLOW_CONFIG_BLUETOOTH);
111     }
112 
113     @Override
onStartInternal()114     protected void onStartInternal() {
115         getContext().registerReceiver(mReceiver, mIntentFilter);
116     }
117 
118     @Override
onStopInternal()119     protected void onStopInternal() {
120         getContext().unregisterReceiver(mReceiver);
121     }
122 
123     @Override
updateState(Preference preference)124     protected void updateState(Preference preference) {
125         preference.setSummary(
126                 BluetoothAdapter.getDefaultAdapter().isEnabled() ? "" : getContext().getString(
127                         R.string.bluetooth_pair_new_device_summary));
128     }
129 
130     @Override
handlePreferenceClicked(Preference preference)131     protected boolean handlePreferenceClicked(Preference preference) {
132         // Enable the adapter if it is not on (user is notified via summary message).
133         BluetoothAdapter.getDefaultAdapter().enable();
134         return false; // Don't handle so that preference framework will launch pairing fragment.
135     }
136 }
137