• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2024 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.connecteddevice.display;
18 
19 import android.content.Context;
20 import android.graphics.drawable.Drawable;
21 import android.os.UserHandle;
22 
23 import androidx.annotation.NonNull;
24 import androidx.annotation.Nullable;
25 import androidx.annotation.VisibleForTesting;
26 import androidx.preference.Preference;
27 
28 import com.android.settings.R;
29 import com.android.settings.connecteddevice.DevicePreferenceCallback;
30 import com.android.settings.connecteddevice.display.ExternalDisplaySettingsConfiguration.DisplayListener;
31 import com.android.settings.connecteddevice.display.ExternalDisplaySettingsConfiguration.Injector;
32 import com.android.settings.core.SubSettingLauncher;
33 import com.android.settings.overlay.FeatureFactory;
34 import com.android.settingslib.RestrictedLockUtils;
35 import com.android.settingslib.RestrictedLockUtilsInternal;
36 import com.android.settingslib.RestrictedPreference;
37 import com.android.settingslib.core.instrumentation.MetricsFeatureProvider;
38 
39 public class ExternalDisplayUpdater {
40 
41     private static final String PREF_KEY = "external_display_settings";
42     private final int mMetricsCategory;
43     @NonNull
44     private final MetricsFeatureProvider mMetricsFeatureProvider;
45     @NonNull
46     private final Runnable mUpdateRunnable = this::update;
47     @NonNull
48     private final DevicePreferenceCallback mDevicePreferenceCallback;
49     @Nullable
50     private RestrictedPreference mPreference;
51     @Nullable
52     private Injector mInjector;
53     private final DisplayListener mListener =  new DisplayListener() {
54         @Override
55         public void update(int displayId) {
56             refreshPreference();
57         }
58     };
59 
ExternalDisplayUpdater(@onNull DevicePreferenceCallback callback, int metricsCategory)60     public ExternalDisplayUpdater(@NonNull DevicePreferenceCallback callback, int metricsCategory) {
61         mDevicePreferenceCallback = callback;
62         mMetricsCategory = metricsCategory;
63         mMetricsFeatureProvider = FeatureFactory.getFeatureFactory().getMetricsFeatureProvider();
64     }
65 
66     /**
67      * Set the context to generate the {@link Preference}, so it could get the correct theme.
68      */
initPreference(@onNull Context context)69     public void initPreference(@NonNull Context context) {
70         initPreference(context, new Injector(context));
71     }
72 
73     @VisibleForTesting
initPreference(@onNull Context context, Injector injector)74     void initPreference(@NonNull Context context, Injector injector) {
75         mInjector = injector;
76         mPreference = new RestrictedPreference(context, null /* AttributeSet */);
77         mPreference.setTitle(R.string.external_display_settings_title);
78         mPreference.setSummary(getSummary());
79         mPreference.setIcon(getDrawable(context));
80         mPreference.setKey(PREF_KEY);
81         mPreference.setDisabledByAdmin(checkIfUsbDataSignalingIsDisabled(context));
82         mPreference.setOnPreferenceClickListener((Preference p) -> {
83             mMetricsFeatureProvider.logClickedPreference(p, mMetricsCategory);
84             // New version - uses a separate screen.
85             new SubSettingLauncher(context)
86                     .setDestination(ExternalDisplayPreferenceFragment.class.getName())
87                     .setTitleRes(R.string.external_display_settings_title)
88                     .setSourceMetricsCategory(mMetricsCategory)
89                     .launch();
90             return true;
91         });
92     }
93 
94     /**
95      * Unregister the display listener.
96      */
unregisterCallback()97     public void unregisterCallback() {
98         if (mInjector != null) {
99             mInjector.unregisterDisplayListener(mListener);
100         }
101     }
102 
103     /**
104      * Register the display listener.
105      */
registerCallback()106     public void registerCallback() {
107         if (mInjector != null) {
108             mInjector.registerDisplayListener(mListener);
109         }
110     }
111 
112     @VisibleForTesting
113     @Nullable
checkIfUsbDataSignalingIsDisabled(Context context)114     protected RestrictedLockUtils.EnforcedAdmin checkIfUsbDataSignalingIsDisabled(Context context) {
115         return RestrictedLockUtilsInternal.checkIfUsbDataSignalingIsDisabled(context,
116                     UserHandle.myUserId());
117     }
118 
119     @VisibleForTesting
120     @Nullable
getDrawable(Context context)121     protected Drawable getDrawable(Context context) {
122         return context.getDrawable(R.drawable.ic_external_display_32dp);
123     }
124 
125     @Nullable
getSummary()126     protected CharSequence getSummary() {
127         if (mInjector == null) {
128             return null;
129         }
130         var context = mInjector.getContext();
131         if (context == null) {
132             return null;
133         }
134 
135         var allDisplays = mInjector.getConnectedDisplays();
136         for (var display : allDisplays) {
137             if (display.isEnabled() == DisplayIsEnabled.YES) {
138                 return context.getString(R.string.external_display_on);
139             }
140         }
141         return allDisplays.isEmpty() ? null : context.getString(R.string.external_display_off);
142     }
143 
144     /**
145      * Updates preference, possibly removing it entirely.
146      */
refreshPreference()147     public void refreshPreference() {
148         if (mInjector == null) {
149             return;
150         }
151         unscheduleUpdate();
152         mInjector.getHandler().post(mUpdateRunnable);
153     }
154 
unscheduleUpdate()155     private void unscheduleUpdate() {
156         if (mInjector == null) {
157             return;
158         }
159         mInjector.getHandler().removeCallbacks(mUpdateRunnable);
160     }
161 
update()162     private void update() {
163         var summary = getSummary();
164         if (mPreference == null) {
165             return;
166         }
167         mPreference.setSummary(summary);
168         if (summary != null) {
169             mDevicePreferenceCallback.onDeviceAdded(mPreference);
170         } else {
171             mDevicePreferenceCallback.onDeviceRemoved(mPreference);
172         }
173     }
174 }
175