diff --git a/packages/SystemUI/res/anim/ic_landscape_from_auto_rotate_animation_arrow_bottom.xml b/packages/SystemUI/res/anim/ic_landscape_from_auto_rotate_animation_arrow_bottom.xml new file mode 100644 index 0000000000000..9add90cf1f48f --- /dev/null +++ b/packages/SystemUI/res/anim/ic_landscape_from_auto_rotate_animation_arrow_bottom.xml @@ -0,0 +1,33 @@ + + + + + + + + diff --git a/packages/SystemUI/res/anim/ic_landscape_from_auto_rotate_animation_arrow_top.xml b/packages/SystemUI/res/anim/ic_landscape_from_auto_rotate_animation_arrow_top.xml new file mode 100644 index 0000000000000..9add90cf1f48f --- /dev/null +++ b/packages/SystemUI/res/anim/ic_landscape_from_auto_rotate_animation_arrow_top.xml @@ -0,0 +1,33 @@ + + + + + + + + diff --git a/packages/SystemUI/res/anim/ic_landscape_from_auto_rotate_animation_arrows.xml b/packages/SystemUI/res/anim/ic_landscape_from_auto_rotate_animation_arrows.xml new file mode 100644 index 0000000000000..6c4e133558252 --- /dev/null +++ b/packages/SystemUI/res/anim/ic_landscape_from_auto_rotate_animation_arrows.xml @@ -0,0 +1,63 @@ + + + + + + + + + + + + + + + + diff --git a/packages/SystemUI/res/anim/ic_landscape_from_auto_rotate_animation_body.xml b/packages/SystemUI/res/anim/ic_landscape_from_auto_rotate_animation_body.xml new file mode 100644 index 0000000000000..a8f5ce015421d --- /dev/null +++ b/packages/SystemUI/res/anim/ic_landscape_from_auto_rotate_animation_body.xml @@ -0,0 +1,35 @@ + + + + + + + + diff --git a/packages/SystemUI/res/anim/ic_landscape_from_auto_rotate_animation_device.xml b/packages/SystemUI/res/anim/ic_landscape_from_auto_rotate_animation_device.xml new file mode 100644 index 0000000000000..b9bb42d4134a5 --- /dev/null +++ b/packages/SystemUI/res/anim/ic_landscape_from_auto_rotate_animation_device.xml @@ -0,0 +1,33 @@ + + + + + + + + diff --git a/packages/SystemUI/res/anim/ic_landscape_to_auto_rotate_animation_arrow_bottom.xml b/packages/SystemUI/res/anim/ic_landscape_to_auto_rotate_animation_arrow_bottom.xml new file mode 100644 index 0000000000000..b8823a9495e8f --- /dev/null +++ b/packages/SystemUI/res/anim/ic_landscape_to_auto_rotate_animation_arrow_bottom.xml @@ -0,0 +1,33 @@ + + + + + + + + diff --git a/packages/SystemUI/res/anim/ic_landscape_to_auto_rotate_animation_arrow_top.xml b/packages/SystemUI/res/anim/ic_landscape_to_auto_rotate_animation_arrow_top.xml new file mode 100644 index 0000000000000..b8823a9495e8f --- /dev/null +++ b/packages/SystemUI/res/anim/ic_landscape_to_auto_rotate_animation_arrow_top.xml @@ -0,0 +1,33 @@ + + + + + + + + diff --git a/packages/SystemUI/res/anim/ic_landscape_to_auto_rotate_animation_arrows.xml b/packages/SystemUI/res/anim/ic_landscape_to_auto_rotate_animation_arrows.xml new file mode 100644 index 0000000000000..14c27766325e6 --- /dev/null +++ b/packages/SystemUI/res/anim/ic_landscape_to_auto_rotate_animation_arrows.xml @@ -0,0 +1,63 @@ + + + + + + + + + + + + + + + + diff --git a/packages/SystemUI/res/anim/ic_landscape_to_auto_rotate_animation_body.xml b/packages/SystemUI/res/anim/ic_landscape_to_auto_rotate_animation_body.xml new file mode 100644 index 0000000000000..ea8f9796e54f8 --- /dev/null +++ b/packages/SystemUI/res/anim/ic_landscape_to_auto_rotate_animation_body.xml @@ -0,0 +1,35 @@ + + + + + + + + diff --git a/packages/SystemUI/res/anim/ic_landscape_to_auto_rotate_animation_device.xml b/packages/SystemUI/res/anim/ic_landscape_to_auto_rotate_animation_device.xml new file mode 100644 index 0000000000000..4e3a3563e6ed1 --- /dev/null +++ b/packages/SystemUI/res/anim/ic_landscape_to_auto_rotate_animation_device.xml @@ -0,0 +1,33 @@ + + + + + + + + diff --git a/packages/SystemUI/res/anim/ic_portrait_from_auto_rotate_animation_arrow_bottom.xml b/packages/SystemUI/res/anim/ic_portrait_from_auto_rotate_animation_arrow_bottom.xml new file mode 100644 index 0000000000000..d05c4e1bd4cf4 --- /dev/null +++ b/packages/SystemUI/res/anim/ic_portrait_from_auto_rotate_animation_arrow_bottom.xml @@ -0,0 +1,33 @@ + + + + + + + + diff --git a/packages/SystemUI/res/anim/ic_portrait_from_auto_rotate_animation_arrow_top.xml b/packages/SystemUI/res/anim/ic_portrait_from_auto_rotate_animation_arrow_top.xml new file mode 100644 index 0000000000000..d05c4e1bd4cf4 --- /dev/null +++ b/packages/SystemUI/res/anim/ic_portrait_from_auto_rotate_animation_arrow_top.xml @@ -0,0 +1,33 @@ + + + + + + + + diff --git a/packages/SystemUI/res/anim/ic_portrait_from_auto_rotate_animation_arrows.xml b/packages/SystemUI/res/anim/ic_portrait_from_auto_rotate_animation_arrows.xml new file mode 100644 index 0000000000000..8bcbf1e36a1b0 --- /dev/null +++ b/packages/SystemUI/res/anim/ic_portrait_from_auto_rotate_animation_arrows.xml @@ -0,0 +1,63 @@ + + + + + + + + + + + + + + + + diff --git a/packages/SystemUI/res/anim/ic_portrait_from_auto_rotate_animation_device.xml b/packages/SystemUI/res/anim/ic_portrait_from_auto_rotate_animation_device.xml new file mode 100644 index 0000000000000..79b1827d8c7d9 --- /dev/null +++ b/packages/SystemUI/res/anim/ic_portrait_from_auto_rotate_animation_device.xml @@ -0,0 +1,33 @@ + + + + + + + + diff --git a/packages/SystemUI/res/anim/ic_portrait_from_auto_rotate_animation_device_1.xml b/packages/SystemUI/res/anim/ic_portrait_from_auto_rotate_animation_device_1.xml new file mode 100644 index 0000000000000..a8f5ce015421d --- /dev/null +++ b/packages/SystemUI/res/anim/ic_portrait_from_auto_rotate_animation_device_1.xml @@ -0,0 +1,35 @@ + + + + + + + + diff --git a/packages/SystemUI/res/anim/ic_portrait_to_auto_rotate_animation_arrow_bottom.xml b/packages/SystemUI/res/anim/ic_portrait_to_auto_rotate_animation_arrow_bottom.xml new file mode 100644 index 0000000000000..c3ae6c1a7e9d9 --- /dev/null +++ b/packages/SystemUI/res/anim/ic_portrait_to_auto_rotate_animation_arrow_bottom.xml @@ -0,0 +1,33 @@ + + + + + + + + diff --git a/packages/SystemUI/res/anim/ic_portrait_to_auto_rotate_animation_arrow_top.xml b/packages/SystemUI/res/anim/ic_portrait_to_auto_rotate_animation_arrow_top.xml new file mode 100644 index 0000000000000..c3ae6c1a7e9d9 --- /dev/null +++ b/packages/SystemUI/res/anim/ic_portrait_to_auto_rotate_animation_arrow_top.xml @@ -0,0 +1,33 @@ + + + + + + + + diff --git a/packages/SystemUI/res/anim/ic_portrait_to_auto_rotate_animation_arrows.xml b/packages/SystemUI/res/anim/ic_portrait_to_auto_rotate_animation_arrows.xml new file mode 100644 index 0000000000000..fde172a9032b5 --- /dev/null +++ b/packages/SystemUI/res/anim/ic_portrait_to_auto_rotate_animation_arrows.xml @@ -0,0 +1,63 @@ + + + + + + + + + + + + + + + + diff --git a/packages/SystemUI/res/anim/ic_portrait_to_auto_rotate_animation_device.xml b/packages/SystemUI/res/anim/ic_portrait_to_auto_rotate_animation_device.xml new file mode 100644 index 0000000000000..accf16d73872c --- /dev/null +++ b/packages/SystemUI/res/anim/ic_portrait_to_auto_rotate_animation_device.xml @@ -0,0 +1,33 @@ + + + + + + + + diff --git a/packages/SystemUI/res/anim/ic_portrait_to_auto_rotate_animation_device_1.xml b/packages/SystemUI/res/anim/ic_portrait_to_auto_rotate_animation_device_1.xml new file mode 100644 index 0000000000000..15c67053448c5 --- /dev/null +++ b/packages/SystemUI/res/anim/ic_portrait_to_auto_rotate_animation_device_1.xml @@ -0,0 +1,35 @@ + + + + + + + + diff --git a/packages/SystemUI/res/drawable/ic_landscape_from_auto_rotate.xml b/packages/SystemUI/res/drawable/ic_landscape_from_auto_rotate.xml new file mode 100644 index 0000000000000..bc545bae6e5b3 --- /dev/null +++ b/packages/SystemUI/res/drawable/ic_landscape_from_auto_rotate.xml @@ -0,0 +1,62 @@ + + + + + + + + + + + + + + + + + diff --git a/packages/SystemUI/res/drawable/ic_landscape_from_auto_rotate_animation.xml b/packages/SystemUI/res/drawable/ic_landscape_from_auto_rotate_animation.xml new file mode 100644 index 0000000000000..400a28ba4e7d2 --- /dev/null +++ b/packages/SystemUI/res/drawable/ic_landscape_from_auto_rotate_animation.xml @@ -0,0 +1,34 @@ + + + + + + + + + diff --git a/packages/SystemUI/res/drawable/ic_landscape_to_auto_rotate.xml b/packages/SystemUI/res/drawable/ic_landscape_to_auto_rotate.xml new file mode 100644 index 0000000000000..0bd75d1871ae1 --- /dev/null +++ b/packages/SystemUI/res/drawable/ic_landscape_to_auto_rotate.xml @@ -0,0 +1,66 @@ + + + + + + + + + + + + + + + + + diff --git a/packages/SystemUI/res/drawable/ic_landscape_to_auto_rotate_animation.xml b/packages/SystemUI/res/drawable/ic_landscape_to_auto_rotate_animation.xml new file mode 100644 index 0000000000000..5263eb49df665 --- /dev/null +++ b/packages/SystemUI/res/drawable/ic_landscape_to_auto_rotate_animation.xml @@ -0,0 +1,34 @@ + + + + + + + + + diff --git a/packages/SystemUI/res/drawable/ic_portrait_from_auto_rotate.xml b/packages/SystemUI/res/drawable/ic_portrait_from_auto_rotate.xml new file mode 100644 index 0000000000000..1805a8e33290f --- /dev/null +++ b/packages/SystemUI/res/drawable/ic_portrait_from_auto_rotate.xml @@ -0,0 +1,62 @@ + + + + + + + + + + + + + + + + + diff --git a/packages/SystemUI/res/drawable/ic_portrait_from_auto_rotate_animation.xml b/packages/SystemUI/res/drawable/ic_portrait_from_auto_rotate_animation.xml new file mode 100644 index 0000000000000..565ef269743dc --- /dev/null +++ b/packages/SystemUI/res/drawable/ic_portrait_from_auto_rotate_animation.xml @@ -0,0 +1,34 @@ + + + + + + + + + diff --git a/packages/SystemUI/res/drawable/ic_portrait_to_auto_rotate.xml b/packages/SystemUI/res/drawable/ic_portrait_to_auto_rotate.xml new file mode 100644 index 0000000000000..feb30253cf238 --- /dev/null +++ b/packages/SystemUI/res/drawable/ic_portrait_to_auto_rotate.xml @@ -0,0 +1,66 @@ + + + + + + + + + + + + + + + + + diff --git a/packages/SystemUI/res/drawable/ic_portrait_to_auto_rotate_animation.xml b/packages/SystemUI/res/drawable/ic_portrait_to_auto_rotate_animation.xml new file mode 100644 index 0000000000000..f75617f04befb --- /dev/null +++ b/packages/SystemUI/res/drawable/ic_portrait_to_auto_rotate_animation.xml @@ -0,0 +1,34 @@ + + + + + + + + + diff --git a/packages/SystemUI/res/drawable/ic_qs_rotation_landscape.xml b/packages/SystemUI/res/drawable/ic_qs_rotation_landscape.xml deleted file mode 100644 index 4bb3668f9108c..0000000000000 --- a/packages/SystemUI/res/drawable/ic_qs_rotation_landscape.xml +++ /dev/null @@ -1,25 +0,0 @@ - - - - - diff --git a/packages/SystemUI/res/drawable/ic_qs_rotation_portrait.xml b/packages/SystemUI/res/drawable/ic_qs_rotation_portrait.xml deleted file mode 100644 index f0878c7113643..0000000000000 --- a/packages/SystemUI/res/drawable/ic_qs_rotation_portrait.xml +++ /dev/null @@ -1,25 +0,0 @@ - - - - - diff --git a/packages/SystemUI/res/drawable/ic_qs_rotation_unlocked.xml b/packages/SystemUI/res/drawable/ic_qs_rotation_unlocked.xml deleted file mode 100644 index 94b3a6baf1cfa..0000000000000 --- a/packages/SystemUI/res/drawable/ic_qs_rotation_unlocked.xml +++ /dev/null @@ -1,24 +0,0 @@ - - - - diff --git a/packages/SystemUI/res/interpolator/ic_landscape_from_auto_rotate_arrows_rotation_interpolator.xml b/packages/SystemUI/res/interpolator/ic_landscape_from_auto_rotate_arrows_rotation_interpolator.xml new file mode 100644 index 0000000000000..76f5667f5fcc8 --- /dev/null +++ b/packages/SystemUI/res/interpolator/ic_landscape_from_auto_rotate_arrows_rotation_interpolator.xml @@ -0,0 +1,18 @@ + + + diff --git a/packages/SystemUI/res/interpolator/ic_landscape_to_auto_rotate_arrows_rotation_interpolator.xml b/packages/SystemUI/res/interpolator/ic_landscape_to_auto_rotate_arrows_rotation_interpolator.xml new file mode 100644 index 0000000000000..ac27e4dae3739 --- /dev/null +++ b/packages/SystemUI/res/interpolator/ic_landscape_to_auto_rotate_arrows_rotation_interpolator.xml @@ -0,0 +1,18 @@ + + + diff --git a/packages/SystemUI/res/values/ids.xml b/packages/SystemUI/res/values/ids.xml index 4e93cd8dfc529..4a9eb5586d984 100644 --- a/packages/SystemUI/res/values/ids.xml +++ b/packages/SystemUI/res/values/ids.xml @@ -35,5 +35,6 @@ + diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSTile.java b/packages/SystemUI/src/com/android/systemui/qs/QSTile.java index 6ef6e9e634ff7..2a66484fb556f 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/QSTile.java +++ b/packages/SystemUI/src/com/android/systemui/qs/QSTile.java @@ -18,11 +18,13 @@ package com.android.systemui.qs; import android.content.Context; import android.content.Intent; +import android.graphics.drawable.AnimatedVectorDrawable; import android.graphics.drawable.Drawable; import android.os.Handler; import android.os.Looper; import android.os.Message; import android.util.Log; +import android.util.SparseArray; import android.view.View; import android.view.ViewGroup; @@ -299,10 +301,91 @@ public abstract class QSTile implements Listenable { } } + public static abstract class Icon { + abstract public Drawable getDrawable(Context context); + + @Override + public int hashCode() { + return Icon.class.hashCode(); + } + } + + public static class ResourceIcon extends Icon { + private static final SparseArray ICONS = new SparseArray(); + + private final int mResId; + + private ResourceIcon(int resId) { + mResId = resId; + } + + public static Icon get(int resId) { + Icon icon = ICONS.get(resId); + if (icon == null) { + icon = new ResourceIcon(resId); + ICONS.put(resId, icon); + } + return icon; + } + + @Override + public Drawable getDrawable(Context context) { + return context.getDrawable(mResId); + } + + @Override + public boolean equals(Object o) { + return o instanceof ResourceIcon && ((ResourceIcon) o).mResId == mResId; + } + + @Override + public String toString() { + return String.format("ResourceIcon[resId=0x%08x]", mResId); + } + } + + protected class AnimationIcon extends ResourceIcon { + private boolean mAllowAnimation; + + public AnimationIcon(int resId) { + super(resId); + } + + public void setAllowAnimation(boolean allowAnimation) { + mAllowAnimation = allowAnimation; + } + + @Override + public Drawable getDrawable(Context context) { + // workaround: get a clean state for every new AVD + final AnimatedVectorDrawable d = (AnimatedVectorDrawable) super.getDrawable(context) + .getConstantState().newDrawable(); + d.start(); + if (mAllowAnimation) { + mAllowAnimation = false; + } else { + d.stop(); // skip directly to end state + } + return d; + } + } + + protected enum UserBoolean { + USER_TRUE(true, true), + USER_FALSE(true, false), + BACKGROUND_TRUE(false, true), + BACKGROUND_FALSE(false, false); + public final boolean value; + public final boolean userInitiated; + private UserBoolean(boolean userInitiated, boolean value) { + this.value = value; + this.userInitiated = userInitiated; + } + } + public static class State { public boolean visible; - public int iconId; - public Drawable icon; + public Icon icon; public String label; public String contentDescription; public String dualLabelContentDescription; @@ -312,7 +395,6 @@ public abstract class QSTile implements Listenable { if (other == null) throw new IllegalArgumentException(); if (!other.getClass().equals(getClass())) throw new IllegalArgumentException(); final boolean changed = other.visible != visible - || other.iconId != iconId || !Objects.equals(other.icon, icon) || !Objects.equals(other.label, label) || !Objects.equals(other.contentDescription, contentDescription) @@ -320,7 +402,6 @@ public abstract class QSTile implements Listenable { || !Objects.equals(other.dualLabelContentDescription, dualLabelContentDescription); other.visible = visible; - other.iconId = iconId; other.icon = icon; other.label = label; other.contentDescription = contentDescription; @@ -335,9 +416,8 @@ public abstract class QSTile implements Listenable { } protected StringBuilder toStringBuilder() { - final StringBuilder sb = new StringBuilder( getClass().getSimpleName()).append('['); + final StringBuilder sb = new StringBuilder(getClass().getSimpleName()).append('['); sb.append("visible=").append(visible); - sb.append(",iconId=").append(iconId); sb.append(",icon=").append(icon); sb.append(",label=").append(label); sb.append(",contentDescription=").append(contentDescription); diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSTileView.java b/packages/SystemUI/src/com/android/systemui/qs/QSTileView.java index d5c90d0668bb2..6b7bdd61a761e 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/QSTileView.java +++ b/packages/SystemUI/src/com/android/systemui/qs/QSTileView.java @@ -21,6 +21,7 @@ import android.content.res.Configuration; import android.content.res.Resources; import android.content.res.TypedArray; import android.graphics.Typeface; +import android.graphics.drawable.Animatable; import android.graphics.drawable.Drawable; import android.graphics.drawable.RippleDrawable; import android.os.Handler; @@ -39,6 +40,8 @@ import com.android.systemui.FontSizeUtils; import com.android.systemui.R; import com.android.systemui.qs.QSTile.State; +import java.util.Objects; + /** View that represents a standard quick settings tile. **/ public class QSTileView extends ViewGroup { private static final Typeface CONDENSED = Typeface.create("sans-serif-condensed", @@ -285,16 +288,7 @@ public class QSTileView extends ViewGroup { protected void handleStateChanged(QSTile.State state) { if (mIcon instanceof ImageView) { - ImageView iv = (ImageView) mIcon; - if (state.icon != null) { - iv.setImageDrawable(state.icon); - } else if (state.iconId > 0) { - iv.setImageResource(state.iconId); - } - Drawable drawable = iv.getDrawable(); - if (state.autoMirrorDrawable && drawable != null) { - drawable.setAutoMirrored(true); - } + setIcon((ImageView) mIcon, state); } if (mDual) { mDualLabel.setText(state.label); @@ -306,6 +300,22 @@ public class QSTileView extends ViewGroup { } } + protected void setIcon(ImageView iv, QSTile.State state) { + if (!Objects.equals(state.icon, iv.getTag(R.id.qs_icon_tag))) { + Drawable d = state.icon != null ? state.icon.getDrawable(mContext) : null; + if (d != null && state.autoMirrorDrawable) { + d.setAutoMirrored(true); + } + iv.setImageDrawable(d); + iv.setTag(R.id.qs_icon_tag, state.icon); + if (d instanceof Animatable) { + if (!iv.isShown()) { + ((Animatable) d).stop(); // skip directly to end state + } + } + } + } + public void onStateChanged(QSTile.State state) { mHandler.obtainMessage(H.STATE_CHANGED, state).sendToTarget(); } diff --git a/packages/SystemUI/src/com/android/systemui/qs/SignalTileView.java b/packages/SystemUI/src/com/android/systemui/qs/SignalTileView.java index cfcd74e8cf473..9ac79440ac45f 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/SignalTileView.java +++ b/packages/SystemUI/src/com/android/systemui/qs/SignalTileView.java @@ -104,7 +104,7 @@ public final class SignalTileView extends QSTileView { protected void handleStateChanged(QSTile.State state) { super.handleStateChanged(state); final SignalState s = (SignalState) state; - mSignal.setImageResource(s.iconId); + setIcon(mSignal, s); if (s.overlayIconId > 0) { mOverlay.setVisibility(VISIBLE); mOverlay.setImageResource(s.overlayIconId); diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/AirplaneModeTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/AirplaneModeTile.java index 51401c8c96663..cd44a2bb20034 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/tiles/AirplaneModeTile.java +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/AirplaneModeTile.java @@ -68,11 +68,11 @@ public class AirplaneModeTile extends QSTile { state.visible = true; state.label = mContext.getString(R.string.quick_settings_airplane_mode_label); if (airplaneMode) { - state.iconId = R.drawable.ic_qs_airplane_on; + state.icon = ResourceIcon.get(R.drawable.ic_qs_airplane_on); state.contentDescription = mContext.getString( R.string.accessibility_quick_settings_airplane_on); } else { - state.iconId = R.drawable.ic_qs_airplane_off; + state.icon = ResourceIcon.get(R.drawable.ic_qs_airplane_off); state.contentDescription = mContext.getString( R.string.accessibility_quick_settings_airplane_off); } diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/BluetoothTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/BluetoothTile.java index 84bfb8fddca17..4d77348179410 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/tiles/BluetoothTile.java +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/BluetoothTile.java @@ -92,17 +92,17 @@ public class BluetoothTile extends QSTile { if (enabled) { state.label = null; if (connected) { - state.iconId = R.drawable.ic_qs_bluetooth_connected; + state.icon = ResourceIcon.get(R.drawable.ic_qs_bluetooth_connected); state.contentDescription = mContext.getString( R.string.accessibility_quick_settings_bluetooth_connected); state.label = mController.getLastDeviceName(); } else if (connecting) { - state.iconId = R.drawable.ic_qs_bluetooth_connecting; + state.icon = ResourceIcon.get(R.drawable.ic_qs_bluetooth_connecting); state.contentDescription = mContext.getString( R.string.accessibility_quick_settings_bluetooth_connecting); state.label = mContext.getString(R.string.quick_settings_bluetooth_label); } else { - state.iconId = R.drawable.ic_qs_bluetooth_on; + state.icon = ResourceIcon.get(R.drawable.ic_qs_bluetooth_on); state.contentDescription = mContext.getString( R.string.accessibility_quick_settings_bluetooth_on); } @@ -110,7 +110,7 @@ public class BluetoothTile extends QSTile { state.label = mContext.getString(R.string.quick_settings_bluetooth_label); } } else { - state.iconId = R.drawable.ic_qs_bluetooth_off; + state.icon = ResourceIcon.get(R.drawable.ic_qs_bluetooth_off); state.label = mContext.getString(R.string.quick_settings_bluetooth_label); state.contentDescription = mContext.getString( R.string.accessibility_quick_settings_bluetooth_off); diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/CastTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/CastTile.java index 8304291368081..5bf6fb5b5e5cc 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/tiles/CastTile.java +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/CastTile.java @@ -107,7 +107,8 @@ public class CastTile extends QSTile { if (!state.value && connecting) { state.label = mContext.getString(R.string.quick_settings_connecting); } - state.iconId = state.value ? R.drawable.ic_qs_cast_on : R.drawable.ic_qs_cast_off; + state.icon = ResourceIcon.get(state.value ? R.drawable.ic_qs_cast_on + : R.drawable.ic_qs_cast_off); mDetailAdapter.updateItems(devices); } diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/CellularTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/CellularTile.java index 359a259ecf0f8..178590be3b23b 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/tiles/CellularTile.java +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/CellularTile.java @@ -87,16 +87,17 @@ public class CellularTile extends QSTile { if (cb == null) return; final Resources r = mContext.getResources(); - state.iconId = cb.noSim ? R.drawable.ic_qs_no_sim + final int iconId = cb.noSim ? R.drawable.ic_qs_no_sim : !cb.enabled || cb.airplaneModeEnabled ? R.drawable.ic_qs_signal_disabled : cb.mobileSignalIconId > 0 ? cb.mobileSignalIconId : R.drawable.ic_qs_signal_no_signal; + state.icon = ResourceIcon.get(iconId); state.isOverlayIconWide = cb.isDataTypeIconWide; state.autoMirrorDrawable = !cb.noSim; state.overlayIconId = cb.enabled && (cb.dataTypeIconId > 0) && !cb.wifiConnected ? cb.dataTypeIconId : 0; - state.filter = state.iconId != R.drawable.ic_qs_no_sim; + state.filter = iconId != R.drawable.ic_qs_no_sim; state.activityIn = cb.enabled && cb.activityIn; state.activityOut = cb.enabled && cb.activityOut; diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/ColorInversionTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/ColorInversionTile.java index 7ba1dc03b2957..b24f8bf87afc3 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/tiles/ColorInversionTile.java +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/ColorInversionTile.java @@ -88,7 +88,8 @@ public class ColorInversionTile extends QSTile { state.visible = enabled || mUsageTracker.isRecentlyUsed(); state.value = enabled; state.label = mContext.getString(R.string.quick_settings_inversion_label); - state.iconId = enabled ? R.drawable.ic_qs_inversion_on : R.drawable.ic_qs_inversion_off; + state.icon = ResourceIcon.get(enabled ? R.drawable.ic_qs_inversion_on + : R.drawable.ic_qs_inversion_off); } @Override diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/FlashlightTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/FlashlightTile.java index e6b7f02586f11..055a6b79e714c 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/tiles/FlashlightTile.java +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/FlashlightTile.java @@ -92,8 +92,8 @@ public class FlashlightTile extends QSTile implements // the camera is not available while it is being used for the flashlight. state.visible = mWasLastOn != 0 || mFlashlightController.isAvailable(); state.label = mHost.getContext().getString(R.string.quick_settings_flashlight_label); - state.iconId = state.value - ? R.drawable.ic_qs_flashlight_on : R.drawable.ic_qs_flashlight_off; + state.icon = ResourceIcon.get(state.value ? R.drawable.ic_qs_flashlight_on + : R.drawable.ic_qs_flashlight_off); int onOrOffId = state.value ? R.string.accessibility_quick_settings_flashlight_on : R.string.accessibility_quick_settings_flashlight_off; 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 b30a1d3c4d911..64dab858031d0 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/tiles/HotspotTile.java +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/HotspotTile.java @@ -71,8 +71,8 @@ public class HotspotTile extends QSTile { state.label = mContext.getString(R.string.quick_settings_hotspot_label); state.value = mController.isHotspotEnabled(); - state.iconId = state.visible && state.value ? R.drawable.ic_qs_hotspot_on - : R.drawable.ic_qs_hotspot_off; + state.icon = ResourceIcon.get(state.visible && state.value ? R.drawable.ic_qs_hotspot_on + : R.drawable.ic_qs_hotspot_off); } @Override diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/IntentTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/IntentTile.java index 58587e651bdc9..6fb9cd8972770 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/tiles/IntentTile.java +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/IntentTile.java @@ -31,6 +31,9 @@ import android.util.Log; import com.android.systemui.qs.QSTile; +import java.util.Arrays; +import java.util.Objects; + public class IntentTile extends QSTile { public static final String PREFIX = "intent("; @@ -96,13 +99,11 @@ public class IntentTile extends QSTile { state.visible = intent.getBooleanExtra("visible", true); state.contentDescription = intent.getStringExtra("contentDescription"); state.label = intent.getStringExtra("label"); - state.iconId = 0; state.icon = null; final byte[] iconBitmap = intent.getByteArrayExtra("iconBitmap"); if (iconBitmap != null) { try { - final Bitmap b = BitmapFactory.decodeByteArray(iconBitmap, 0, iconBitmap.length); - state.icon = new BitmapDrawable(mContext.getResources(), b); + state.icon = new BytesIcon(iconBitmap); } catch (Throwable t) { Log.w(TAG, "Error loading icon bitmap, length " + iconBitmap.length, t); } @@ -111,9 +112,9 @@ public class IntentTile extends QSTile { if (iconId != 0) { final String iconPackage = intent.getStringExtra("iconPackage"); if (!TextUtils.isEmpty(iconPackage)) { - state.icon = getPackageDrawable(iconPackage, iconId); + state.icon = new PackageDrawableIcon(iconPackage, iconId); } else { - state.iconId = iconId; + state.icon = ResourceIcon.get(iconId); } } } @@ -121,19 +122,66 @@ public class IntentTile extends QSTile { mOnClickUri = intent.getStringExtra("onClickUri"); } - private Drawable getPackageDrawable(String pkg, int id) { - try { - return mContext.createPackageContext(pkg, 0).getDrawable(id); - } catch (Throwable t) { - Log.w(TAG, "Error loading package drawable pkg=" + pkg + " id=" + id, t); - return null; - } - } - private final BroadcastReceiver mReceiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { refreshState(intent); } }; + + private static class BytesIcon extends Icon { + private final byte[] mBytes; + + public BytesIcon(byte[] bytes) { + mBytes = bytes; + } + + @Override + public Drawable getDrawable(Context context) { + final Bitmap b = BitmapFactory.decodeByteArray(mBytes, 0, mBytes.length); + return new BitmapDrawable(context.getResources(), b); + } + + @Override + public boolean equals(Object o) { + return o instanceof BytesIcon && Arrays.equals(((BytesIcon) o).mBytes, mBytes); + } + + @Override + public String toString() { + return String.format("BytesIcon[len=%s]", mBytes.length); + } + } + + private class PackageDrawableIcon extends Icon { + private final String mPackage; + private final int mResId; + + public PackageDrawableIcon(String pkg, int resId) { + mPackage = pkg; + mResId = resId; + } + + @Override + public boolean equals(Object o) { + if (!(o instanceof PackageDrawableIcon)) return false; + final PackageDrawableIcon other = (PackageDrawableIcon) o; + return Objects.equals(other.mPackage, mPackage) && other.mResId == mResId; + } + + @Override + public Drawable getDrawable(Context context) { + try { + return context.createPackageContext(mPackage, 0).getDrawable(mResId); + } catch (Throwable t) { + Log.w(TAG, "Error loading package drawable pkg=" + mPackage + " id=" + mResId, t); + return null; + } + } + + @Override + public String toString() { + return String.format("PackageDrawableIcon[pkg=%s,id=0x%08x]", mPackage, mResId); + } + } } diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/LocationTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/LocationTile.java index d1dc5d2b00e7c..81741ce8a8ac3 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/tiles/LocationTile.java +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/LocationTile.java @@ -67,12 +67,12 @@ public class LocationTile extends QSTile { state.visible = !mKeyguard.isShowing(); state.value = locationEnabled; if (locationEnabled) { - state.iconId = R.drawable.ic_qs_location_on; + state.icon = ResourceIcon.get(R.drawable.ic_qs_location_on); state.label = mContext.getString(R.string.quick_settings_location_label); state.contentDescription = mContext.getString( R.string.accessibility_quick_settings_location_on); } else { - state.iconId = R.drawable.ic_qs_location_off; + state.icon = ResourceIcon.get(R.drawable.ic_qs_location_off); state.label = mContext.getString(R.string.quick_settings_location_label); state.contentDescription = mContext.getString( R.string.accessibility_quick_settings_location_off); diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/RotationLockTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/RotationLockTile.java index ae40a4d03899f..49cd14afc944c 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/tiles/RotationLockTile.java +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/RotationLockTile.java @@ -17,7 +17,6 @@ package com.android.systemui.qs.tiles; import android.content.res.Configuration; -import android.content.res.Resources; import com.android.systemui.R; import com.android.systemui.qs.QSTile; @@ -26,6 +25,15 @@ import com.android.systemui.statusbar.policy.RotationLockController.RotationLock /** Quick settings tile: Rotation **/ public class RotationLockTile extends QSTile { + private final AnimationIcon PORTRAIT_TO_AUTO + = new AnimationIcon(R.drawable.ic_portrait_to_auto_rotate_animation); + private final AnimationIcon AUTO_TO_PORTRAIT + = new AnimationIcon(R.drawable.ic_portrait_from_auto_rotate_animation); + + private final AnimationIcon LANDSCAPE_TO_AUTO + = new AnimationIcon(R.drawable.ic_landscape_to_auto_rotate_animation); + private final AnimationIcon AUTO_TO_LANDSCAPE + = new AnimationIcon(R.drawable.ic_landscape_from_auto_rotate_animation); private final RotationLockController mController; @@ -51,30 +59,34 @@ public class RotationLockTile extends QSTile { @Override protected void handleClick() { if (mController == null) return; - mController.setRotationLocked(!mState.value); + final boolean newState = !mState.value; + mController.setRotationLocked(newState); + refreshState(newState ? UserBoolean.USER_TRUE : UserBoolean.USER_FALSE); } @Override protected void handleUpdateState(BooleanState state, Object arg) { if (mController == null) return; - final boolean rotationLocked = mController.isRotationLocked(); + final boolean rotationLocked = arg != null ? ((UserBoolean) arg).value + : mController.isRotationLocked(); + final boolean userInitiated = arg != null ? ((UserBoolean) arg).userInitiated : false; state.visible = mController.isRotationLockAffordanceVisible(); - final Resources res = mContext.getResources(); state.value = rotationLocked; + final boolean portrait = mContext.getResources().getConfiguration().orientation + != Configuration.ORIENTATION_LANDSCAPE; + final AnimationIcon icon; if (rotationLocked) { - final boolean portrait = res.getConfiguration().orientation - != Configuration.ORIENTATION_LANDSCAPE; final int label = portrait ? R.string.quick_settings_rotation_locked_portrait_label : R.string.quick_settings_rotation_locked_landscape_label; - final int icon = portrait ? R.drawable.ic_qs_rotation_portrait - : R.drawable.ic_qs_rotation_landscape; state.label = mContext.getString(label); - state.icon = mContext.getDrawable(icon); + icon = portrait ? AUTO_TO_PORTRAIT : AUTO_TO_LANDSCAPE; } else { state.label = mContext.getString(R.string.quick_settings_rotation_unlocked_label); - state.icon = res.getDrawable(R.drawable.ic_qs_rotation_unlocked); + icon = portrait ? PORTRAIT_TO_AUTO : LANDSCAPE_TO_AUTO; } - state.contentDescription = getAccessibilityString( + icon.setAllowAnimation(userInitiated); + state.icon = icon; + state.contentDescription = getAccessibilityString(rotationLocked, R.string.accessibility_rotation_lock_on_portrait, R.string.accessibility_rotation_lock_on_landscape, R.string.accessibility_rotation_lock_off); @@ -83,14 +95,16 @@ public class RotationLockTile extends QSTile { /** * Get the correct accessibility string based on the state * + * @param locked Whether or not rotation is locked. * @param idWhenPortrait The id which should be used when locked in portrait. * @param idWhenLandscape The id which should be used when locked in landscape. * @param idWhenOff The id which should be used when the rotation lock is off. * @return */ - private String getAccessibilityString(int idWhenPortrait, int idWhenLandscape, int idWhenOff) { + private String getAccessibilityString(boolean locked, int idWhenPortrait, int idWhenLandscape, + int idWhenOff) { int stringID; - if (mState.value) { + if (locked) { final boolean portrait = mContext.getResources().getConfiguration().orientation != Configuration.ORIENTATION_LANDSCAPE; stringID = portrait ? idWhenPortrait: idWhenLandscape; @@ -102,7 +116,7 @@ public class RotationLockTile extends QSTile { @Override protected String composeChangeAnnouncement() { - return getAccessibilityString( + return getAccessibilityString(mState.value, R.string.accessibility_rotation_lock_on_portrait_changed, R.string.accessibility_rotation_lock_on_landscape_changed, R.string.accessibility_rotation_lock_off_changed); @@ -111,7 +125,8 @@ public class RotationLockTile extends QSTile { private final RotationLockControllerCallback mCallback = new RotationLockControllerCallback() { @Override public void onRotationLockStateChanged(boolean rotationLocked, boolean affordanceVisible) { - refreshState(); + refreshState(rotationLocked ? UserBoolean.BACKGROUND_TRUE + : UserBoolean.BACKGROUND_FALSE); } }; } diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/WifiTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/WifiTile.java index 20c4ee8c406f2..7aa884effe7ab 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/tiles/WifiTile.java +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/WifiTile.java @@ -120,19 +120,19 @@ public class WifiTile extends QSTile { final String signalContentDescription; final Resources r = mContext.getResources(); if (!state.enabled) { - state.iconId = R.drawable.ic_qs_wifi_disabled; + state.icon = ResourceIcon.get(R.drawable.ic_qs_wifi_disabled); state.label = r.getString(R.string.quick_settings_wifi_label); signalContentDescription = r.getString(R.string.accessibility_wifi_off); } else if (wifiConnected) { - state.iconId = cb.wifiSignalIconId; + state.icon = ResourceIcon.get(cb.wifiSignalIconId); state.label = removeDoubleQuotes(cb.enabledDesc); signalContentDescription = cb.wifiSignalContentDescription; } else if (wifiNotConnected) { - state.iconId = R.drawable.ic_qs_wifi_0; + state.icon = ResourceIcon.get(R.drawable.ic_qs_wifi_0); state.label = r.getString(R.string.quick_settings_wifi_label); signalContentDescription = r.getString(R.string.accessibility_no_wifi); } else { - state.iconId = R.drawable.ic_qs_wifi_no_network; + state.icon = ResourceIcon.get(R.drawable.ic_qs_wifi_no_network); state.label = r.getString(R.string.quick_settings_wifi_label); signalContentDescription = r.getString(R.string.accessibility_wifi_off); }