From e645aee45a7784d772e4bdf846dd2e77335f30f2 Mon Sep 17 00:00:00 2001 From: Jason Monk Date: Fri, 31 Mar 2017 13:19:26 -0400 Subject: [PATCH] QS: Add transient icon for hotspot Will make the loading time more clear. Test: visual Bug: 32270851 Change-Id: I0ea7591da132ff65fb7fc16b03b2891891e66598 --- .../android/systemui/plugins/qs/QSTile.java | 4 ++ ...c_hotspot_transient_circle_1_animation.xml | 35 +++++++++++++ ...c_hotspot_transient_circle_2_animation.xml | 35 +++++++++++++ ...c_hotspot_transient_circle_3_animation.xml | 28 +++++++++++ .../res/drawable/ic_hotspot_transient.xml | 50 +++++++++++++++++++ .../ic_hotspot_transient_animation.xml | 14 ++++++ .../systemui/qs/tileimpl/QSIconViewImpl.java | 15 ++++-- .../systemui/qs/tiles/HotspotTile.java | 13 +++-- .../statusbar/policy/HotspotController.java | 2 + .../policy/HotspotControllerImpl.java | 36 +++++++++---- .../utils/leaks/FakeHotspotController.java | 5 ++ 11 files changed, 220 insertions(+), 17 deletions(-) create mode 100644 packages/SystemUI/res/anim/ic_hotspot_transient_circle_1_animation.xml create mode 100644 packages/SystemUI/res/anim/ic_hotspot_transient_circle_2_animation.xml create mode 100644 packages/SystemUI/res/anim/ic_hotspot_transient_circle_3_animation.xml create mode 100644 packages/SystemUI/res/drawable/ic_hotspot_transient.xml create mode 100644 packages/SystemUI/res/drawable/ic_hotspot_transient_animation.xml 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) {