summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--packages/SystemUI/res/values/strings.xml5
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/tiles/HotspotTile.java54
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/AutoTileManager.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/policy/HotspotController.java6
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/policy/HotspotControllerImpl.java99
-rw-r--r--packages/SystemUI/tests/AndroidManifest.xml1
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/utils/leaks/FakeHotspotController.java5
8 files changed, 150 insertions, 24 deletions
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index 8d6b38f87801..edf19fd2dddc 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -764,6 +764,11 @@
<string name="quick_settings_tethering_label">Tethering</string>
<!-- QuickSettings: Hotspot. [CHAR LIMIT=NONE] -->
<string name="quick_settings_hotspot_label">Hotspot</string>
+ <!-- QuickSettings: Hotspot: Secondary label for how many devices are connected to the hotspot [CHAR LIMIT=NONE] -->
+ <plurals name="quick_settings_hotspot_num_devices">
+ <item quantity="one">%d device</item>
+ <item quantity="other">%d devices</item>
+ </plurals>
<!-- QuickSettings: Notifications [CHAR LIMIT=NONE] -->
<string name="quick_settings_notifications_label">Notifications</string>
<!-- QuickSettings: Flashlight [CHAR LIMIT=NONE] -->
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/HotspotTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/HotspotTile.java
index 910b6b174062..e1b58fe4c2d6 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/HotspotTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/HotspotTile.java
@@ -16,6 +16,7 @@
package com.android.systemui.qs.tiles;
+import android.annotation.Nullable;
import android.content.ComponentName;
import android.content.Intent;
import android.content.IntentFilter;
@@ -37,7 +38,7 @@ import com.android.systemui.statusbar.policy.HotspotController;
/** Quick settings tile: Hotspot **/
public class HotspotTile extends QSTileImpl<AirplaneBooleanState> {
static final Intent TETHER_SETTINGS = new Intent().setComponent(new ComponentName(
- "com.android.settings", "com.android.settings.TetherSettings"));
+ "com.android.settings", "com.android.settings.TetherSettings"));
private final Icon mEnabledStatic = ResourceIcon.get(R.drawable.ic_hotspot);
private final Icon mUnavailable = ResourceIcon.get(R.drawable.ic_hotspot_unavailable);
@@ -115,11 +116,19 @@ public class HotspotTile extends QSTileImpl<AirplaneBooleanState> {
state.label = mContext.getString(R.string.quick_settings_hotspot_label);
checkIfRestrictionEnforcedByAdminOnly(state, UserManager.DISALLOW_CONFIG_TETHERING);
- if (arg instanceof Boolean) {
- state.value = (boolean) arg;
+
+ final int numConnectedDevices;
+ if (arg instanceof CallbackInfo) {
+ CallbackInfo info = (CallbackInfo) arg;
+ state.value = info.enabled;
+ numConnectedDevices = info.numConnectedDevices;
} else {
state.value = mController.isHotspotEnabled();
+ numConnectedDevices = mController.getNumConnectedDevices();
}
+
+ state.secondaryLabel = getSecondaryLabel(state.value, numConnectedDevices);
+
state.icon = mEnabledStatic;
state.isAirplaneMode = mAirplaneMode.getValue() != 0;
state.isTransient = mController.isHotspotTransient();
@@ -133,6 +142,18 @@ public class HotspotTile extends QSTileImpl<AirplaneBooleanState> {
: state.value || state.isTransient ? Tile.STATE_ACTIVE : Tile.STATE_INACTIVE;
}
+ @Nullable
+ private String getSecondaryLabel(boolean enabled, int numConnectedDevices) {
+ if (numConnectedDevices > 0 && enabled) {
+ return mContext.getResources().getQuantityString(
+ R.plurals.quick_settings_hotspot_num_devices,
+ numConnectedDevices,
+ numConnectedDevices);
+ }
+
+ return null;
+ }
+
@Override
public int getMetricsCategory() {
return MetricsEvent.QS_HOTSPOT;
@@ -148,9 +169,30 @@ public class HotspotTile extends QSTileImpl<AirplaneBooleanState> {
}
private final class Callback implements HotspotController.Callback {
+ final CallbackInfo mCallbackInfo = new CallbackInfo();
+
@Override
- public void onHotspotChanged(boolean enabled) {
- refreshState(enabled);
+ public void onHotspotChanged(boolean enabled, int numConnectedDevices) {
+ mCallbackInfo.enabled = enabled;
+ mCallbackInfo.numConnectedDevices = numConnectedDevices;
+ refreshState(mCallbackInfo);
}
- };
+ }
+
+ /**
+ * Holder for any hotspot state info that needs to passed from the callback to
+ * {@link #handleUpdateState(State, Object)}.
+ */
+ protected static final class CallbackInfo {
+ boolean enabled;
+ int numConnectedDevices;
+
+ @Override
+ public String toString() {
+ return new StringBuilder("CallbackInfo[")
+ .append("enabled=").append(enabled)
+ .append(",numConnectedDevices=").append(numConnectedDevices)
+ .append(']').toString();
+ }
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/AutoTileManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/AutoTileManager.java
index 149ec0b3a56a..36f9f6b79417 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/AutoTileManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/AutoTileManager.java
@@ -127,7 +127,7 @@ public class AutoTileManager {
private final HotspotController.Callback mHotspotCallback = new Callback() {
@Override
- public void onHotspotChanged(boolean enabled) {
+ public void onHotspotChanged(boolean enabled, int numDevices) {
if (mAutoTracker.isAdded(HOTSPOT)) return;
if (enabled) {
mHost.addTile(HOTSPOT);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java
index 6857337e5c10..20b501821a97 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java
@@ -665,7 +665,7 @@ public class PhoneStatusBarPolicy implements Callback, Callbacks,
private final HotspotController.Callback mHotspotCallback = new HotspotController.Callback() {
@Override
- public void onHotspotChanged(boolean enabled) {
+ public void onHotspotChanged(boolean enabled, int numDevices) {
mIconController.setIconVisibility(mSlotHotspot, enabled);
}
};
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/HotspotController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/HotspotController.java
index 6457209a407b..830b50e35490 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/HotspotController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/HotspotController.java
@@ -26,7 +26,9 @@ public interface HotspotController extends CallbackController<Callback>, Dumpabl
void setHotspotEnabled(boolean enabled);
boolean isHotspotSupported();
- public interface Callback {
- void onHotspotChanged(boolean enabled);
+ int getNumConnectedDevices();
+
+ interface Callback {
+ void onHotspotChanged(boolean enabled, int numDevices);
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/HotspotControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/HotspotControllerImpl.java
index 1ebb986e4488..8792b4f3cc4c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/HotspotControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/HotspotControllerImpl.java
@@ -23,31 +23,35 @@ import android.content.Intent;
import android.content.IntentFilter;
import android.net.ConnectivityManager;
import android.net.wifi.WifiManager;
-import android.os.Handler;
import android.os.UserManager;
import android.util.Log;
+import com.android.systemui.Dependency;
+
import java.io.FileDescriptor;
import java.io.PrintWriter;
import java.util.ArrayList;
-public class HotspotControllerImpl implements HotspotController {
+public class HotspotControllerImpl implements HotspotController, WifiManager.SoftApCallback {
private static final String TAG = "HotspotController";
private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
- private final ArrayList<Callback> mCallbacks = new ArrayList<Callback>();
- private final Receiver mReceiver = new Receiver();
+ private final ArrayList<Callback> mCallbacks = new ArrayList<>();
+ private final WifiStateReceiver mWifiStateReceiver = new WifiStateReceiver();
private final ConnectivityManager mConnectivityManager;
+ private final WifiManager mWifiManager;
private final Context mContext;
private int mHotspotState;
+ private int mNumConnectedDevices;
private boolean mWaitingForCallback;
public HotspotControllerImpl(Context context) {
mContext = context;
- mConnectivityManager = (ConnectivityManager) context.getSystemService(
- Context.CONNECTIVITY_SERVICE);
+ mConnectivityManager =
+ (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
+ mWifiManager = (WifiManager) context.getSystemService(Context.WIFI_SERVICE);
}
@Override
@@ -84,7 +88,8 @@ public class HotspotControllerImpl implements HotspotController {
if (callback == null || mCallbacks.contains(callback)) return;
if (DEBUG) Log.d(TAG, "addCallback " + callback);
mCallbacks.add(callback);
- mReceiver.setListening(!mCallbacks.isEmpty());
+
+ updateWifiStateListeners(!mCallbacks.isEmpty());
}
}
@@ -94,7 +99,26 @@ public class HotspotControllerImpl implements HotspotController {
if (DEBUG) Log.d(TAG, "removeCallback " + callback);
synchronized (mCallbacks) {
mCallbacks.remove(callback);
- mReceiver.setListening(!mCallbacks.isEmpty());
+
+ updateWifiStateListeners(!mCallbacks.isEmpty());
+ }
+ }
+
+ /**
+ * Updates the wifi state receiver to either start or stop listening to get updates to the
+ * hotspot status. Additionally starts listening to wifi manager state to track the number of
+ * connected devices.
+ *
+ * @param shouldListen whether we should start listening to various wifi statuses
+ */
+ private void updateWifiStateListeners(boolean shouldListen) {
+ mWifiStateReceiver.setListening(shouldListen);
+ if (shouldListen) {
+ mWifiManager.registerSoftApCallback(
+ this,
+ Dependency.get(Dependency.MAIN_HANDLER));
+ } else {
+ mWifiManager.unregisterSoftApCallback(this);
}
}
@@ -116,20 +140,55 @@ public class HotspotControllerImpl implements HotspotController {
if (DEBUG) Log.d(TAG, "Starting tethering");
mConnectivityManager.startTethering(
ConnectivityManager.TETHERING_WIFI, false, callback);
- fireCallback(isHotspotEnabled());
+ fireHotspotChangedCallback(isHotspotEnabled());
} else {
mConnectivityManager.stopTethering(ConnectivityManager.TETHERING_WIFI);
}
}
- private void fireCallback(boolean isEnabled) {
+ @Override
+ public int getNumConnectedDevices() {
+ return mNumConnectedDevices;
+ }
+
+ /**
+ * Sends a hotspot changed callback with the new enabled status. Wraps
+ * {@link #fireHotspotChangedCallback(boolean, int)} and assumes that the number of devices has
+ * not changed.
+ *
+ * @param enabled whether the hotspot is enabled
+ */
+ private void fireHotspotChangedCallback(boolean enabled) {
+ fireHotspotChangedCallback(enabled, mNumConnectedDevices);
+ }
+
+ /**
+ * Sends a hotspot changed callback with the new enabled status & the number of devices
+ * connected to the hotspot. Be careful when calling over multiple threads, especially if one of
+ * them is the main thread (as it can be blocked).
+ *
+ * @param enabled whether the hotspot is enabled
+ * @param numConnectedDevices number of devices connected to the hotspot
+ */
+ private void fireHotspotChangedCallback(boolean enabled, int numConnectedDevices) {
synchronized (mCallbacks) {
for (Callback callback : mCallbacks) {
- callback.onHotspotChanged(isEnabled);
+ callback.onHotspotChanged(enabled, numConnectedDevices);
}
}
}
+ @Override
+ public void onStateChanged(int state, int failureReason) {
+ // Do nothing - we don't care about changing anything here.
+ }
+
+ @Override
+ public void onNumClientsChanged(int numConnectedDevices) {
+ mNumConnectedDevices = numConnectedDevices;
+ fireHotspotChangedCallback(isHotspotEnabled(), numConnectedDevices);
+ }
+
private final class OnStartTetheringCallback extends
ConnectivityManager.OnStartTetheringCallback {
@Override
@@ -143,12 +202,15 @@ public class HotspotControllerImpl implements HotspotController {
public void onTetheringFailed() {
if (DEBUG) Log.d(TAG, "onTetheringFailed");
mWaitingForCallback = false;
- fireCallback(isHotspotEnabled());
+ fireHotspotChangedCallback(isHotspotEnabled());
// TODO: Show error.
}
}
- private final class Receiver extends BroadcastReceiver {
+ /**
+ * Class to listen in on wifi state and update the hotspot state
+ */
+ private final class WifiStateReceiver extends BroadcastReceiver {
private boolean mRegistered;
public void setListening(boolean listening) {
@@ -170,8 +232,17 @@ public class HotspotControllerImpl implements HotspotController {
int state = intent.getIntExtra(
WifiManager.EXTRA_WIFI_AP_STATE, WifiManager.WIFI_AP_STATE_FAILED);
if (DEBUG) Log.d(TAG, "onReceive " + state);
+
+ // Update internal hotspot state for tracking before using any enabled/callback methods.
mHotspotState = state;
- fireCallback(mHotspotState == WifiManager.WIFI_AP_STATE_ENABLED);
+
+ if (!isHotspotEnabled()) {
+ // Reset num devices if the hotspot is no longer enabled so we don't get ghost
+ // counters.
+ mNumConnectedDevices = 0;
+ }
+
+ fireHotspotChangedCallback(isHotspotEnabled());
}
}
}
diff --git a/packages/SystemUI/tests/AndroidManifest.xml b/packages/SystemUI/tests/AndroidManifest.xml
index 859dc2f18dc6..f5e079ca9d61 100644
--- a/packages/SystemUI/tests/AndroidManifest.xml
+++ b/packages/SystemUI/tests/AndroidManifest.xml
@@ -47,6 +47,7 @@
<uses-permission android:name="android.permission.MANAGE_ACTIVITY_STACKS" />
<uses-permission android:name="android.permission.REAL_GET_TASKS" />
<uses-permission android:name="android.permission.INTERNAL_SYSTEM_WINDOW" />
+ <uses-permission android:name="android.permission.NETWORK_SETTINGS" />
<application>
<uses-library android:name="android.test.runner" />
diff --git a/packages/SystemUI/tests/src/com/android/systemui/utils/leaks/FakeHotspotController.java b/packages/SystemUI/tests/src/com/android/systemui/utils/leaks/FakeHotspotController.java
index 54911473fc1c..016160aea433 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/utils/leaks/FakeHotspotController.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/utils/leaks/FakeHotspotController.java
@@ -44,4 +44,9 @@ public class FakeHotspotController extends BaseLeakChecker<Callback> implements
public boolean isHotspotSupported() {
return false;
}
+
+ @Override
+ public int getNumConnectedDevices() {
+ return 0;
+ }
}