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.settings.uwb;
18 
19 import static androidx.lifecycle.Lifecycle.Event.ON_START;
20 import static androidx.lifecycle.Lifecycle.Event.ON_STOP;
21 
22 import android.content.BroadcastReceiver;
23 import android.content.Context;
24 import android.content.Intent;
25 import android.content.IntentFilter;
26 import android.content.pm.PackageManager;
27 import android.os.Handler;
28 import android.provider.Settings;
29 import android.uwb.UwbManager;
30 import android.uwb.UwbManager.AdapterStateCallback;
31 
32 import androidx.lifecycle.LifecycleObserver;
33 import androidx.lifecycle.OnLifecycleEvent;
34 import androidx.preference.Preference;
35 import androidx.preference.PreferenceScreen;
36 
37 import com.android.internal.annotations.VisibleForTesting;
38 import com.android.settings.R;
39 import com.android.settings.core.TogglePreferenceController;
40 
41 import java.util.concurrent.Executor;
42 import java.util.concurrent.Executors;
43 
44 /** Controller for "UWB" toggle. */
45 public class UwbPreferenceController extends TogglePreferenceController implements
46         AdapterStateCallback, LifecycleObserver {
47     @VisibleForTesting
48     static final String KEY_UWB_SETTINGS = "uwb_settings";
49     @VisibleForTesting
50     UwbManager mUwbManager;
51     @VisibleForTesting
52     boolean mAirplaneModeOn;
53     @VisibleForTesting
54     private final BroadcastReceiver mAirplaneModeChangedReceiver;
55     private final Executor mExecutor;
56     private final Handler mHandler;
57     private Preference mPreference;
58 
UwbPreferenceController(Context context, String key)59     public UwbPreferenceController(Context context, String key) {
60         super(context, key);
61         mExecutor = Executors.newSingleThreadExecutor();
62         mHandler = new Handler(context.getMainLooper());
63         if (isUwbSupportedOnDevice()) {
64             mUwbManager = context.getSystemService(UwbManager.class);
65         }
66         mAirplaneModeOn = Settings.Global.getInt(mContext.getContentResolver(),
67                 Settings.Global.AIRPLANE_MODE_ON, 0) == 1;
68         mAirplaneModeChangedReceiver = new BroadcastReceiver() {
69             @Override
70             public void onReceive(Context context, Intent intent) {
71                 mAirplaneModeOn = Settings.Global.getInt(mContext.getContentResolver(),
72                         Settings.Global.AIRPLANE_MODE_ON, 0) == 1;
73                 updateState(mPreference);
74             }
75         };
76     }
77 
78     @VisibleForTesting
isUwbSupportedOnDevice()79     boolean isUwbSupportedOnDevice() {
80         return mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_UWB);
81     }
82 
83     @Override
getAvailabilityStatus()84     public int getAvailabilityStatus() {
85         if (!isUwbSupportedOnDevice()) {
86             return UNSUPPORTED_ON_DEVICE;
87         } else if (mAirplaneModeOn) {
88             return DISABLED_DEPENDENT_SETTING;
89         } else {
90             return AVAILABLE;
91         }
92     }
93 
94     @Override
displayPreference(PreferenceScreen screen)95     public void displayPreference(PreferenceScreen screen) {
96         super.displayPreference(screen);
97         mPreference = screen.findPreference(getPreferenceKey());
98     }
99 
100     @Override
isChecked()101     public boolean isChecked() {
102         int state = mUwbManager.getAdapterState();
103         return state == STATE_ENABLED_ACTIVE || state == STATE_ENABLED_INACTIVE;
104     }
105 
106     @Override
setChecked(boolean isChecked)107     public boolean setChecked(boolean isChecked) {
108         mAirplaneModeOn = Settings.Global.getInt(mContext.getContentResolver(),
109                 Settings.Global.AIRPLANE_MODE_ON, 0) == 1;
110         if (isUwbSupportedOnDevice()) {
111             if (mAirplaneModeOn) {
112                 mUwbManager.setUwbEnabled(false);
113             } else {
114                 mUwbManager.setUwbEnabled(isChecked);
115             }
116         }
117         return true;
118     }
119 
120     @Override
onStateChanged(int state, int reason)121     public void onStateChanged(int state, int reason) {
122         Runnable runnable = () -> updateState(mPreference);
123         mHandler.post(runnable);
124     }
125 
126     /** Called when activity starts being displayed to user. */
127     @OnLifecycleEvent(ON_START)
onStart()128     public void onStart() {
129         if (isUwbSupportedOnDevice()) {
130             mUwbManager.registerAdapterStateCallback(mExecutor, this);
131         }
132         if (mAirplaneModeChangedReceiver != null) {
133             mContext.registerReceiver(mAirplaneModeChangedReceiver,
134                     new IntentFilter(Intent.ACTION_AIRPLANE_MODE_CHANGED));
135         }
136         refreshSummary(mPreference);
137     }
138 
139     /** Called when activity stops being displayed to user. */
140     @OnLifecycleEvent(ON_STOP)
onStop()141     public void onStop() {
142         if (isUwbSupportedOnDevice()) {
143             mUwbManager.unregisterAdapterStateCallback(this);
144         }
145         if (mAirplaneModeChangedReceiver != null) {
146             mContext.unregisterReceiver(mAirplaneModeChangedReceiver);
147         }
148     }
149 
150     @Override
updateState(Preference preference)151     public void updateState(Preference preference) {
152         super.updateState(preference);
153         preference.setEnabled(!mAirplaneModeOn);
154         refreshSummary(preference);
155     }
156 
157     @Override
getSummary()158     public CharSequence getSummary() {
159         if (mAirplaneModeOn) {
160             return mContext.getResources().getString(R.string.uwb_settings_summary_airplane_mode);
161         } else {
162             return mContext.getResources().getString(R.string.uwb_settings_summary);
163         }
164     }
165 
166     @Override
getSliceHighlightMenuRes()167     public int getSliceHighlightMenuRes() {
168         return R.string.menu_key_connected_devices;
169     }
170 }
171 
172