diff --git a/packages/SystemUI/plugin/src/com/android/systemui/plugins/qs/QSTile.java b/packages/SystemUI/plugin/src/com/android/systemui/plugins/qs/QSTile.java
index 7bb31c09a5c2e..7d78c089b0899 100644
--- a/packages/SystemUI/plugin/src/com/android/systemui/plugins/qs/QSTile.java
+++ b/packages/SystemUI/plugin/src/com/android/systemui/plugins/qs/QSTile.java
@@ -105,6 +105,7 @@ public interface QSTile {
public CharSequence dualLabelContentDescription;
public boolean disabledByPolicy;
public boolean dualTarget = false;
+ public boolean isTransient = false;
public String expandedAccessibilityClassName;
public boolean copyTo(State other) {
@@ -119,6 +120,7 @@ public interface QSTile {
expandedAccessibilityClassName)
|| !Objects.equals(other.disabledByPolicy, disabledByPolicy)
|| !Objects.equals(other.state, state)
+ || !Objects.equals(other.isTransient, isTransient)
|| !Objects.equals(other.dualTarget, dualTarget);
other.icon = icon;
other.label = label;
@@ -128,6 +130,7 @@ public interface QSTile {
other.disabledByPolicy = disabledByPolicy;
other.state = state;
other.dualTarget = dualTarget;
+ other.isTransient = isTransient;
return changed;
}
@@ -145,6 +148,7 @@ public interface QSTile {
sb.append(",expandedAccessibilityClassName=").append(expandedAccessibilityClassName);
sb.append(",disabledByPolicy=").append(disabledByPolicy);
sb.append(",dualTarget=").append(dualTarget);
+ sb.append(",isTransient=").append(isTransient);
sb.append(",state=").append(state);
return sb.append(']');
}
diff --git a/packages/SystemUI/res/anim/ic_hotspot_transient_circle_1_animation.xml b/packages/SystemUI/res/anim/ic_hotspot_transient_circle_1_animation.xml
new file mode 100644
index 0000000000000..3444747f3a245
--- /dev/null
+++ b/packages/SystemUI/res/anim/ic_hotspot_transient_circle_1_animation.xml
@@ -0,0 +1,35 @@
+
+
+
+
+
+
+
+
+
diff --git a/packages/SystemUI/res/anim/ic_hotspot_transient_circle_2_animation.xml b/packages/SystemUI/res/anim/ic_hotspot_transient_circle_2_animation.xml
new file mode 100644
index 0000000000000..06e08cd9486f8
--- /dev/null
+++ b/packages/SystemUI/res/anim/ic_hotspot_transient_circle_2_animation.xml
@@ -0,0 +1,35 @@
+
+
+
+
+
+
+
+
+
diff --git a/packages/SystemUI/res/anim/ic_hotspot_transient_circle_3_animation.xml b/packages/SystemUI/res/anim/ic_hotspot_transient_circle_3_animation.xml
new file mode 100644
index 0000000000000..6b01687904b8c
--- /dev/null
+++ b/packages/SystemUI/res/anim/ic_hotspot_transient_circle_3_animation.xml
@@ -0,0 +1,28 @@
+
+
+
+
+
+
+
+
diff --git a/packages/SystemUI/res/drawable/ic_hotspot_transient.xml b/packages/SystemUI/res/drawable/ic_hotspot_transient.xml
new file mode 100644
index 0000000000000..8c1f7ea79c44d
--- /dev/null
+++ b/packages/SystemUI/res/drawable/ic_hotspot_transient.xml
@@ -0,0 +1,50 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/packages/SystemUI/res/drawable/ic_hotspot_transient_animation.xml b/packages/SystemUI/res/drawable/ic_hotspot_transient_animation.xml
new file mode 100644
index 0000000000000..b2945f187595d
--- /dev/null
+++ b/packages/SystemUI/res/drawable/ic_hotspot_transient_animation.xml
@@ -0,0 +1,14 @@
+
+
+
+
+
+
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSIconViewImpl.java b/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSIconViewImpl.java
index 6e2add4937798..661c92178b45a 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSIconViewImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSIconViewImpl.java
@@ -22,6 +22,8 @@ import android.content.res.ColorStateList;
import android.content.res.Resources;
import android.graphics.Color;
import android.graphics.drawable.Animatable;
+import android.graphics.drawable.Animatable2;
+import android.graphics.drawable.Animatable2.AnimationCallback;
import android.graphics.drawable.Drawable;
import android.view.View;
import android.widget.ImageView;
@@ -96,11 +98,16 @@ public class QSIconViewImpl extends QSIconView {
iv.setImageDrawable(d);
iv.setTag(R.id.qs_icon_tag, state.icon);
iv.setPadding(0, padding, 0, padding);
- if (d instanceof Animatable && iv.isShown()) {
- Animatable a = (Animatable) d;
+ if (d instanceof Animatable2) {
+ Animatable2 a = (Animatable2) d;
a.start();
- if (!iv.isShown()) {
- a.stop(); // skip directly to end state
+ if (state.isTransient) {
+ a.registerAnimationCallback(new AnimationCallback() {
+ @Override
+ public void onAnimationEnd(Drawable drawable) {
+ a.start();
+ }
+ });
}
}
}
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 5c3f65c471bf2..40f2c4b19be4e 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/HotspotTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/HotspotTile.java
@@ -25,7 +25,6 @@ import android.provider.Settings.Global;
import android.service.quicksettings.Tile;
import android.widget.Switch;
-import com.android.internal.logging.MetricsLogger;
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
import com.android.systemui.Dependency;
import com.android.systemui.R;
@@ -43,6 +42,7 @@ public class HotspotTile extends QSTileImpl {
private final AnimationIcon mEnable =
new AnimationIcon(R.drawable.ic_hotspot_enable_animation,
R.drawable.ic_hotspot_disable);
+ private final Icon mEnabledStatic = ResourceIcon.get(R.drawable.ic_hotspot_disable);
private final AnimationIcon mDisable =
new AnimationIcon(R.drawable.ic_hotspot_disable_animation,
R.drawable.ic_hotspot_enable);
@@ -124,10 +124,15 @@ public class HotspotTile extends QSTileImpl {
} else {
state.value = mController.isHotspotEnabled();
}
- state.icon = state.value ? mEnable : mDisable;
+ state.icon = !state.value ? mDisable
+ : state.isTransient ? mEnabledStatic
+ : mEnable;
boolean wasAirplane = state.isAirplaneMode;
state.isAirplaneMode = mAirplaneMode.getValue() != 0;
- if (state.isAirplaneMode) {
+ state.isTransient = mController.isHotspotTransient();
+ if (state.isTransient) {
+ state.icon = ResourceIcon.get(R.drawable.ic_hotspot_transient_animation);
+ } else if (state.isAirplaneMode) {
state.icon = mUnavailable;
} else if (wasAirplane) {
state.icon = mDisableNoAnimation;
@@ -135,7 +140,7 @@ public class HotspotTile extends QSTileImpl {
state.expandedAccessibilityClassName = Switch.class.getName();
state.contentDescription = state.label;
state.state = state.isAirplaneMode ? Tile.STATE_UNAVAILABLE
- : state.value ? Tile.STATE_ACTIVE : Tile.STATE_INACTIVE;
+ : state.value || state.isTransient ? Tile.STATE_ACTIVE : Tile.STATE_INACTIVE;
}
@Override
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 0543678814fd3..6457209a407b3 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/HotspotController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/HotspotController.java
@@ -21,6 +21,8 @@ import com.android.systemui.statusbar.policy.HotspotController.Callback;
public interface HotspotController extends CallbackController, Dumpable {
boolean isHotspotEnabled();
+ boolean isHotspotTransient();
+
void setHotspotEnabled(boolean enabled);
boolean isHotspotSupported();
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 4664851053d72..1ebb986e44885 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/HotspotControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/HotspotControllerImpl.java
@@ -23,6 +23,7 @@ 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;
@@ -41,6 +42,7 @@ public class HotspotControllerImpl implements HotspotController {
private final Context mContext;
private int mHotspotState;
+ private boolean mWaitingForCallback;
public HotspotControllerImpl(Context context) {
mContext = context;
@@ -101,22 +103,20 @@ public class HotspotControllerImpl implements HotspotController {
return mHotspotState == WifiManager.WIFI_AP_STATE_ENABLED;
}
- static final class OnStartTetheringCallback extends
- ConnectivityManager.OnStartTetheringCallback {
- @Override
- public void onTetheringStarted() {}
- @Override
- public void onTetheringFailed() {
- // TODO: Show error.
- }
+ @Override
+ public boolean isHotspotTransient() {
+ return mWaitingForCallback || (mHotspotState == WifiManager.WIFI_AP_STATE_ENABLING);
}
@Override
public void setHotspotEnabled(boolean enabled) {
if (enabled) {
OnStartTetheringCallback callback = new OnStartTetheringCallback();
+ mWaitingForCallback = true;
+ if (DEBUG) Log.d(TAG, "Starting tethering");
mConnectivityManager.startTethering(
ConnectivityManager.TETHERING_WIFI, false, callback);
+ fireCallback(isHotspotEnabled());
} else {
mConnectivityManager.stopTethering(ConnectivityManager.TETHERING_WIFI);
}
@@ -130,6 +130,24 @@ public class HotspotControllerImpl implements HotspotController {
}
}
+ private final class OnStartTetheringCallback extends
+ ConnectivityManager.OnStartTetheringCallback {
+ @Override
+ public void onTetheringStarted() {
+ if (DEBUG) Log.d(TAG, "onTetheringStarted");
+ mWaitingForCallback = false;
+ // Don't fire a callback here, instead wait for the next update from wifi.
+ }
+
+ @Override
+ public void onTetheringFailed() {
+ if (DEBUG) Log.d(TAG, "onTetheringFailed");
+ mWaitingForCallback = false;
+ fireCallback(isHotspotEnabled());
+ // TODO: Show error.
+ }
+ }
+
private final class Receiver extends BroadcastReceiver {
private boolean mRegistered;
@@ -149,9 +167,9 @@ public class HotspotControllerImpl implements HotspotController {
@Override
public void onReceive(Context context, Intent intent) {
- if (DEBUG) Log.d(TAG, "onReceive " + intent.getAction());
int state = intent.getIntExtra(
WifiManager.EXTRA_WIFI_AP_STATE, WifiManager.WIFI_AP_STATE_FAILED);
+ if (DEBUG) Log.d(TAG, "onReceive " + state);
mHotspotState = state;
fireCallback(mHotspotState == WifiManager.WIFI_AP_STATE_ENABLED);
}
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 69e236172fef7..54911473fc1cb 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
@@ -30,6 +30,11 @@ public class FakeHotspotController extends BaseLeakChecker implements
return false;
}
+ @Override
+ public boolean isHotspotTransient() {
+ return false;
+ }
+
@Override
public void setHotspotEnabled(boolean enabled) {