blob: b7e07f8283219d879a7fd4e8cdea9f6e17bc3fde [file] [log] [blame]
John Spurlockaf8d6c42014-05-07 17:49:08 -04001/*
2 * Copyright (C) 2014 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
17package com.android.systemui.qs.tiles;
18
Rohan Shahe4071122018-01-22 15:16:09 -080019import android.annotation.Nullable;
Jake Whatleyac7c5d22017-02-02 20:25:12 -050020import android.content.ComponentName;
Jason Monk76c67aa2016-02-19 14:49:42 -050021import android.content.Intent;
Sudheer Shankab6fc9312016-01-27 19:59:03 +000022import android.os.UserManager;
Jason Monk49a27962016-05-25 14:22:01 -040023import android.provider.Settings.Global;
jackqdyulei76471a52016-12-05 15:03:56 -080024import android.service.quicksettings.Tile;
Julia Reynolds20aef8a2016-05-04 16:44:08 -040025import android.widget.Switch;
26
Tamas Berghammer383db5eb2016-06-22 15:21:38 +010027import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
John Spurlockaf8d6c42014-05-07 17:49:08 -040028import com.android.systemui.R;
Amin Shaikhd03a7432018-03-01 15:46:55 -050029import com.android.systemui.plugins.qs.QSTile.AirplaneBooleanState;
Jason Monk49a27962016-05-25 14:22:01 -040030import com.android.systemui.qs.GlobalSetting;
Jason Monk702e2eb2017-03-03 16:53:44 -050031import com.android.systemui.qs.QSHost;
Jason Monk702e2eb2017-03-03 16:53:44 -050032import com.android.systemui.qs.tileimpl.QSTileImpl;
Rohan Shah815fa982018-03-01 13:15:13 -080033import com.android.systemui.statusbar.policy.DataSaverController;
Jason Monk51e4dc02014-07-22 12:00:47 -040034import com.android.systemui.statusbar.policy.HotspotController;
John Spurlockaf8d6c42014-05-07 17:49:08 -040035
Jason Monk5d577202018-12-26 15:43:06 -050036import javax.inject.Inject;
37
John Spurlockaf8d6c42014-05-07 17:49:08 -040038/** Quick settings tile: Hotspot **/
Jason Monk702e2eb2017-03-03 16:53:44 -050039public class HotspotTile extends QSTileImpl<AirplaneBooleanState> {
Rohan Shah815fa982018-03-01 13:15:13 -080040 private static final Intent TETHER_SETTINGS = new Intent().setComponent(new ComponentName(
Rohan Shahe4071122018-01-22 15:16:09 -080041 "com.android.settings", "com.android.settings.TetherSettings"));
Jake Whatleyac7c5d22017-02-02 20:25:12 -050042
Evan Lairdbcdd0462017-05-15 12:51:34 -040043 private final Icon mEnabledStatic = ResourceIcon.get(R.drawable.ic_hotspot);
Jason Monkab17c982016-06-20 12:39:38 -040044
Rohan Shah815fa982018-03-01 13:15:13 -080045 private final HotspotController mHotspotController;
46 private final DataSaverController mDataSaverController;
47
48 private final HotspotAndDataSaverCallbacks mCallbacks = new HotspotAndDataSaverCallbacks();
Jason Monk49a27962016-05-25 14:22:01 -040049 private final GlobalSetting mAirplaneMode;
50 private boolean mListening;
John Spurlockaf8d6c42014-05-07 17:49:08 -040051
Jason Monk5d577202018-12-26 15:43:06 -050052 @Inject
Jason Monkc0e0e2b2018-12-26 16:47:41 -050053 public HotspotTile(QSHost host, HotspotController hotspotController,
54 DataSaverController dataSaverController) {
John Spurlockaf8d6c42014-05-07 17:49:08 -040055 super(host);
Jason Monkc0e0e2b2018-12-26 16:47:41 -050056 mHotspotController = hotspotController;
57 mDataSaverController = dataSaverController;
Jason Monk49a27962016-05-25 14:22:01 -040058 mAirplaneMode = new GlobalSetting(mContext, mHandler, Global.AIRPLANE_MODE_ON) {
59 @Override
60 protected void handleValueChanged(int value) {
61 refreshState();
62 }
63 };
Jason Monkfa452ef2018-12-26 17:26:10 -050064 mHotspotController.observe(this, mCallbacks);
65 mDataSaverController.observe(this, mCallbacks);
John Spurlockbceed062014-08-10 18:04:16 -040066 }
67
68 @Override
Jason Monk28680c62016-04-19 09:31:20 -040069 public boolean isAvailable() {
Rohan Shah815fa982018-03-01 13:15:13 -080070 return mHotspotController.isHotspotSupported();
Jason Monk28680c62016-04-19 09:31:20 -040071 }
72
73 @Override
John Spurlockbceed062014-08-10 18:04:16 -040074 protected void handleDestroy() {
75 super.handleDestroy();
John Spurlockaf8d6c42014-05-07 17:49:08 -040076 }
77
78 @Override
Jason Monkab17c982016-06-20 12:39:38 -040079 public AirplaneBooleanState newTileState() {
80 return new AirplaneBooleanState();
John Spurlockaf8d6c42014-05-07 17:49:08 -040081 }
82
83 @Override
Jason Monk1c6116c2017-09-06 17:33:01 -040084 public void handleSetListening(boolean listening) {
Jason Monk49a27962016-05-25 14:22:01 -040085 if (mListening == listening) return;
86 mListening = listening;
Jason Monk51e4dc02014-07-22 12:00:47 -040087 if (listening) {
Jason Monk94f682e2016-06-23 13:23:01 -040088 refreshState();
Jason Monk51e4dc02014-07-22 12:00:47 -040089 }
Jason Monk49a27962016-05-25 14:22:01 -040090 mAirplaneMode.setListening(listening);
John Spurlockaf8d6c42014-05-07 17:49:08 -040091 }
92
93 @Override
Jason Monk76c67aa2016-02-19 14:49:42 -050094 public Intent getLongClickIntent() {
Jake Whatleyac7c5d22017-02-02 20:25:12 -050095 return new Intent(TETHER_SETTINGS);
Jason Monk76c67aa2016-02-19 14:49:42 -050096 }
97
98 @Override
John Spurlockaf8d6c42014-05-07 17:49:08 -040099 protected void handleClick() {
Amin Shaikhd03a7432018-03-01 15:46:55 -0500100 final boolean isEnabled = mState.value;
Amin Shaikhc26ab75f2018-04-23 18:29:11 -0400101 if (!isEnabled &&
102 (mAirplaneMode.getValue() != 0 || mDataSaverController.isDataSaverEnabled())) {
Jason Monk49a27962016-05-25 14:22:01 -0400103 return;
104 }
Amin Shaikhd03a7432018-03-01 15:46:55 -0500105 // Immediately enter transient enabling state when turning hotspot on.
106 refreshState(isEnabled ? null : ARG_SHOW_TRANSIENT_ENABLING);
Rohan Shah815fa982018-03-01 13:15:13 -0800107 mHotspotController.setHotspotEnabled(!isEnabled);
John Spurlockaf8d6c42014-05-07 17:49:08 -0400108 }
109
110 @Override
Jason Monk39c98e62016-03-16 09:18:35 -0400111 public CharSequence getTileLabel() {
112 return mContext.getString(R.string.quick_settings_hotspot_label);
113 }
114
115 @Override
Jason Monkab17c982016-06-20 12:39:38 -0400116 protected void handleUpdateState(AirplaneBooleanState state, Object arg) {
Amin Shaikhd03a7432018-03-01 15:46:55 -0500117 final boolean transientEnabling = arg == ARG_SHOW_TRANSIENT_ENABLING;
Jason Monk395617f2017-05-05 14:07:58 -0400118 if (state.slash == null) {
119 state.slash = new SlashState();
120 }
Rohan Shahe4071122018-01-22 15:16:09 -0800121
122 final int numConnectedDevices;
Rohan Shah815fa982018-03-01 13:15:13 -0800123 final boolean isTransient = transientEnabling || mHotspotController.isHotspotTransient();
124 final boolean isDataSaverEnabled;
Rohan Shah1b497b02018-01-24 11:28:37 -0800125
126 checkIfRestrictionEnforcedByAdminOnly(state, UserManager.DISALLOW_CONFIG_TETHERING);
Rohan Shah815fa982018-03-01 13:15:13 -0800127
Rohan Shahe4071122018-01-22 15:16:09 -0800128 if (arg instanceof CallbackInfo) {
Rohan Shah815fa982018-03-01 13:15:13 -0800129 final CallbackInfo info = (CallbackInfo) arg;
130 state.value = transientEnabling || info.isHotspotEnabled;
Rohan Shahe4071122018-01-22 15:16:09 -0800131 numConnectedDevices = info.numConnectedDevices;
Rohan Shah815fa982018-03-01 13:15:13 -0800132 isDataSaverEnabled = info.isDataSaverEnabled;
Julia Reynoldsb8a46a62015-07-14 13:36:30 -0400133 } else {
Rohan Shah815fa982018-03-01 13:15:13 -0800134 state.value = transientEnabling || mHotspotController.isHotspotEnabled();
135 numConnectedDevices = mHotspotController.getNumConnectedDevices();
136 isDataSaverEnabled = mDataSaverController.isDataSaverEnabled();
Julia Reynoldsb8a46a62015-07-14 13:36:30 -0400137 }
Rohan Shahe4071122018-01-22 15:16:09 -0800138
Jason Monk395617f2017-05-05 14:07:58 -0400139 state.icon = mEnabledStatic;
Rohan Shah1b497b02018-01-24 11:28:37 -0800140 state.label = mContext.getString(R.string.quick_settings_hotspot_label);
Jason Monkab17c982016-06-20 12:39:38 -0400141 state.isAirplaneMode = mAirplaneMode.getValue() != 0;
Rohan Shah1b497b02018-01-24 11:28:37 -0800142 state.isTransient = isTransient;
Jason Monk395617f2017-05-05 14:07:58 -0400143 state.slash.isSlashed = !state.value && !state.isTransient;
Jason Monke645aee2017-03-31 13:19:26 -0400144 if (state.isTransient) {
145 state.icon = ResourceIcon.get(R.drawable.ic_hotspot_transient_animation);
Jason Monk49a27962016-05-25 14:22:01 -0400146 }
Jason Monk702e2eb2017-03-03 16:53:44 -0500147 state.expandedAccessibilityClassName = Switch.class.getName();
Julia Reynolds20aef8a2016-05-04 16:44:08 -0400148 state.contentDescription = state.label;
Rohan Shah815fa982018-03-01 13:15:13 -0800149
150 final boolean isTileUnavailable = (state.isAirplaneMode || isDataSaverEnabled);
151 final boolean isTileActive = (state.value || state.isTransient);
Rohan Shah2c23b132018-03-09 13:41:11 -0800152
153 if (isTileUnavailable) {
154 state.state = Tile.STATE_UNAVAILABLE;
155 } else {
156 state.state = isTileActive ? Tile.STATE_ACTIVE : Tile.STATE_INACTIVE;
157 }
158
159 state.secondaryLabel = getSecondaryLabel(
160 isTileActive, isTransient, isDataSaverEnabled, numConnectedDevices);
Jason Monk51e4dc02014-07-22 12:00:47 -0400161 }
162
Rohan Shahe4071122018-01-22 15:16:09 -0800163 @Nullable
Rohan Shah2c23b132018-03-09 13:41:11 -0800164 private String getSecondaryLabel(boolean isActive, boolean isTransient,
165 boolean isDataSaverEnabled, int numConnectedDevices) {
Rohan Shah1b497b02018-01-24 11:28:37 -0800166 if (isTransient) {
167 return mContext.getString(R.string.quick_settings_hotspot_secondary_label_transient);
Rohan Shah2c23b132018-03-09 13:41:11 -0800168 } else if (isDataSaverEnabled) {
169 return mContext.getString(
170 R.string.quick_settings_hotspot_secondary_label_data_saver_enabled);
171 } else if (numConnectedDevices > 0 && isActive) {
Rohan Shahe4071122018-01-22 15:16:09 -0800172 return mContext.getResources().getQuantityString(
Rohan Shah1b497b02018-01-24 11:28:37 -0800173 R.plurals.quick_settings_hotspot_secondary_label_num_devices,
Rohan Shahe4071122018-01-22 15:16:09 -0800174 numConnectedDevices,
175 numConnectedDevices);
176 }
177
178 return null;
179 }
180
Selim Cinek4fda7b22014-08-18 22:07:25 +0200181 @Override
Chris Wren457a21c2015-05-06 17:50:34 -0400182 public int getMetricsCategory() {
Chris Wrenf6e9228b2016-01-26 18:04:35 -0500183 return MetricsEvent.QS_HOTSPOT;
Chris Wren457a21c2015-05-06 17:50:34 -0400184 }
185
186 @Override
Selim Cinek4fda7b22014-08-18 22:07:25 +0200187 protected String composeChangeAnnouncement() {
188 if (mState.value) {
189 return mContext.getString(R.string.accessibility_quick_settings_hotspot_changed_on);
190 } else {
191 return mContext.getString(R.string.accessibility_quick_settings_hotspot_changed_off);
192 }
193 }
194
Rohan Shah815fa982018-03-01 13:15:13 -0800195 /**
196 * Listens to changes made to hotspot and data saver states (to toggle tile availability).
197 */
198 private final class HotspotAndDataSaverCallbacks implements HotspotController.Callback,
199 DataSaverController.Listener {
200 CallbackInfo mCallbackInfo = new CallbackInfo();
Rohan Shahe4071122018-01-22 15:16:09 -0800201
Jason Monk51e4dc02014-07-22 12:00:47 -0400202 @Override
Rohan Shah815fa982018-03-01 13:15:13 -0800203 public void onDataSaverChanged(boolean isDataSaving) {
204 mCallbackInfo.isDataSaverEnabled = isDataSaving;
205 refreshState(mCallbackInfo);
206 }
207
208 @Override
209 public void onHotspotChanged(boolean enabled, int numDevices) {
210 mCallbackInfo.isHotspotEnabled = enabled;
211 mCallbackInfo.numConnectedDevices = numDevices;
Rohan Shahe4071122018-01-22 15:16:09 -0800212 refreshState(mCallbackInfo);
Jason Monk51e4dc02014-07-22 12:00:47 -0400213 }
Rohan Shahe4071122018-01-22 15:16:09 -0800214 }
215
216 /**
217 * Holder for any hotspot state info that needs to passed from the callback to
218 * {@link #handleUpdateState(State, Object)}.
219 */
220 protected static final class CallbackInfo {
Rohan Shah815fa982018-03-01 13:15:13 -0800221 boolean isHotspotEnabled;
Rohan Shahe4071122018-01-22 15:16:09 -0800222 int numConnectedDevices;
Rohan Shah815fa982018-03-01 13:15:13 -0800223 boolean isDataSaverEnabled;
Rohan Shahe4071122018-01-22 15:16:09 -0800224
225 @Override
226 public String toString() {
227 return new StringBuilder("CallbackInfo[")
Rohan Shah815fa982018-03-01 13:15:13 -0800228 .append("isHotspotEnabled=").append(isHotspotEnabled)
Rohan Shahe4071122018-01-22 15:16:09 -0800229 .append(",numConnectedDevices=").append(numConnectedDevices)
Rohan Shah815fa982018-03-01 13:15:13 -0800230 .append(",isDataSaverEnabled=").append(isDataSaverEnabled)
Rohan Shahe4071122018-01-22 15:16:09 -0800231 .append(']').toString();
232 }
233 }
John Spurlockaf8d6c42014-05-07 17:49:08 -0400234}