Let RemoteViews nest children, allow ViewFlipper.
This change allows applications to nest children RemoteViews inside an existing set of RemoteViews. These nested views are inflated and treated as addView() calls. This change also allows ViewFlipper through RemoteViews, and adds logic surpress flipping when the parent window is detached or behind the lockscreen. Also fixes ViewAnimator to observe the measureAllChildren flag when set. Fixes http://b/2239905
This commit is contained in:
@@ -1967,6 +1967,17 @@
|
||||
visibility="public"
|
||||
>
|
||||
</field>
|
||||
<field name="autoStart"
|
||||
type="int"
|
||||
transient="false"
|
||||
volatile="false"
|
||||
value="16843446"
|
||||
static="true"
|
||||
final="true"
|
||||
deprecated="not deprecated"
|
||||
visibility="public"
|
||||
>
|
||||
</field>
|
||||
<field name="autoText"
|
||||
type="int"
|
||||
transient="false"
|
||||
@@ -189616,6 +189627,21 @@
|
||||
<parameter name="parcel" type="android.os.Parcel">
|
||||
</parameter>
|
||||
</constructor>
|
||||
<method name="addView"
|
||||
return="void"
|
||||
abstract="false"
|
||||
native="false"
|
||||
synchronized="false"
|
||||
static="false"
|
||||
final="false"
|
||||
deprecated="not deprecated"
|
||||
visibility="public"
|
||||
>
|
||||
<parameter name="viewId" type="int">
|
||||
</parameter>
|
||||
<parameter name="nestedView" type="android.widget.RemoteViews">
|
||||
</parameter>
|
||||
</method>
|
||||
<method name="apply"
|
||||
return="android.view.View"
|
||||
abstract="false"
|
||||
@@ -189692,6 +189718,19 @@
|
||||
<parameter name="v" type="android.view.View">
|
||||
</parameter>
|
||||
</method>
|
||||
<method name="removeAllViews"
|
||||
return="void"
|
||||
abstract="false"
|
||||
native="false"
|
||||
synchronized="false"
|
||||
static="false"
|
||||
final="false"
|
||||
deprecated="not deprecated"
|
||||
visibility="public"
|
||||
>
|
||||
<parameter name="viewId" type="int">
|
||||
</parameter>
|
||||
</method>
|
||||
<method name="setBitmap"
|
||||
return="void"
|
||||
abstract="false"
|
||||
@@ -196277,6 +196316,17 @@
|
||||
<parameter name="attrs" type="android.util.AttributeSet">
|
||||
</parameter>
|
||||
</constructor>
|
||||
<method name="isAutoStart"
|
||||
return="boolean"
|
||||
abstract="false"
|
||||
native="false"
|
||||
synchronized="false"
|
||||
static="false"
|
||||
final="false"
|
||||
deprecated="not deprecated"
|
||||
visibility="public"
|
||||
>
|
||||
</method>
|
||||
<method name="isFlipping"
|
||||
return="boolean"
|
||||
abstract="false"
|
||||
@@ -196288,6 +196338,19 @@
|
||||
visibility="public"
|
||||
>
|
||||
</method>
|
||||
<method name="setAutoStart"
|
||||
return="void"
|
||||
abstract="false"
|
||||
native="false"
|
||||
synchronized="false"
|
||||
static="false"
|
||||
final="false"
|
||||
deprecated="not deprecated"
|
||||
visibility="public"
|
||||
>
|
||||
<parameter name="autoStart" type="boolean">
|
||||
</parameter>
|
||||
</method>
|
||||
<method name="setFlipInterval"
|
||||
return="void"
|
||||
abstract="false"
|
||||
|
||||
@@ -457,6 +457,46 @@ public class RemoteViews implements Parcelable, Filter {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Equivalent to calling {@link ViewGroup#addView(View)} after inflating the
|
||||
* given {@link RemoteViews}, or calling {@link ViewGroup#removeAllViews()}
|
||||
* when null. This allows users to build "nested" {@link RemoteViews}.
|
||||
*/
|
||||
private class ViewGroupAction extends Action {
|
||||
public ViewGroupAction(int viewId, RemoteViews nestedViews) {
|
||||
this.viewId = viewId;
|
||||
this.nestedViews = nestedViews;
|
||||
}
|
||||
|
||||
public ViewGroupAction(Parcel parcel) {
|
||||
viewId = parcel.readInt();
|
||||
nestedViews = parcel.readParcelable(null);
|
||||
}
|
||||
|
||||
public void writeToParcel(Parcel dest, int flags) {
|
||||
dest.writeInt(TAG);
|
||||
dest.writeInt(viewId);
|
||||
dest.writeParcelable(nestedViews, 0 /* no flags */);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void apply(View root) {
|
||||
final Context context = root.getContext();
|
||||
final ViewGroup target = (ViewGroup) root.findViewById(viewId);
|
||||
if (nestedViews != null) {
|
||||
// Inflate nested views and add as children
|
||||
target.addView(nestedViews.apply(context, target));
|
||||
} else if (target != null) {
|
||||
// Clear all children when nested views omitted
|
||||
target.removeAllViews();
|
||||
}
|
||||
}
|
||||
|
||||
int viewId;
|
||||
RemoteViews nestedViews;
|
||||
|
||||
public final static int TAG = 4;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new RemoteViews object that will display the views contained
|
||||
@@ -493,6 +533,9 @@ public class RemoteViews implements Parcelable, Filter {
|
||||
case ReflectionAction.TAG:
|
||||
mActions.add(new ReflectionAction(parcel));
|
||||
break;
|
||||
case ViewGroupAction.TAG:
|
||||
mActions.add(new ViewGroupAction(parcel));
|
||||
break;
|
||||
default:
|
||||
throw new ActionException("Tag " + tag + " not found");
|
||||
}
|
||||
@@ -519,7 +562,31 @@ public class RemoteViews implements Parcelable, Filter {
|
||||
}
|
||||
mActions.add(a);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Equivalent to calling {@link ViewGroup#addView(View)} after inflating the
|
||||
* given {@link RemoteViews}. This allows users to build "nested"
|
||||
* {@link RemoteViews}. In cases where consumers of {@link RemoteViews} may
|
||||
* recycle layouts, use {@link #removeAllViews(int)} to clear any existing
|
||||
* children.
|
||||
*
|
||||
* @param viewId The id of the parent {@link ViewGroup} to add child into.
|
||||
* @param nestedView {@link RemoteViews} that describes the child.
|
||||
*/
|
||||
public void addView(int viewId, RemoteViews nestedView) {
|
||||
addAction(new ViewGroupAction(viewId, nestedView));
|
||||
}
|
||||
|
||||
/**
|
||||
* Equivalent to calling {@link ViewGroup#removeAllViews()}.
|
||||
*
|
||||
* @param viewId The id of the parent {@link ViewGroup} to remove all
|
||||
* children from.
|
||||
*/
|
||||
public void removeAllViews(int viewId) {
|
||||
addAction(new ViewGroupAction(viewId, null));
|
||||
}
|
||||
|
||||
/**
|
||||
* Equivalent to calling View.setVisibility
|
||||
*
|
||||
|
||||
@@ -43,7 +43,7 @@ public class ViewAnimator extends FrameLayout {
|
||||
|
||||
public ViewAnimator(Context context) {
|
||||
super(context);
|
||||
initViewAnimator();
|
||||
initViewAnimator(context, null);
|
||||
}
|
||||
|
||||
public ViewAnimator(Context context, AttributeSet attrs) {
|
||||
@@ -61,11 +61,28 @@ public class ViewAnimator extends FrameLayout {
|
||||
}
|
||||
a.recycle();
|
||||
|
||||
initViewAnimator();
|
||||
initViewAnimator(context, attrs);
|
||||
}
|
||||
|
||||
private void initViewAnimator() {
|
||||
mMeasureAllChildren = true;
|
||||
/**
|
||||
* Initialize this {@link ViewAnimator}, possibly setting
|
||||
* {@link #setMeasureAllChildren(boolean)} based on {@link FrameLayout} flags.
|
||||
*/
|
||||
private void initViewAnimator(Context context, AttributeSet attrs) {
|
||||
if (attrs == null) {
|
||||
// For compatibility, always measure children when undefined.
|
||||
mMeasureAllChildren = true;
|
||||
return;
|
||||
}
|
||||
|
||||
// For compatibility, default to measure children, but allow XML
|
||||
// attribute to override.
|
||||
final TypedArray a = context.obtainStyledAttributes(attrs,
|
||||
com.android.internal.R.styleable.FrameLayout);
|
||||
final boolean measureAllChildren = a.getBoolean(
|
||||
com.android.internal.R.styleable.FrameLayout_measureAllChildren, true);
|
||||
setMeasureAllChildren(measureAllChildren);
|
||||
a.recycle();
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -16,12 +16,15 @@
|
||||
|
||||
package android.widget;
|
||||
|
||||
|
||||
import android.content.BroadcastReceiver;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.IntentFilter;
|
||||
import android.content.res.TypedArray;
|
||||
import android.os.Handler;
|
||||
import android.os.Message;
|
||||
import android.util.AttributeSet;
|
||||
import android.util.Log;
|
||||
import android.widget.RemoteViews.RemoteView;
|
||||
|
||||
/**
|
||||
@@ -30,10 +33,22 @@ import android.widget.RemoteViews.RemoteView;
|
||||
* requested, can automatically flip between each child at a regular interval.
|
||||
*
|
||||
* @attr ref android.R.styleable#ViewFlipper_flipInterval
|
||||
* @attr ref android.R.styleable#ViewFlipper_autoStart
|
||||
*/
|
||||
@RemoteView
|
||||
public class ViewFlipper extends ViewAnimator {
|
||||
private int mFlipInterval = 3000;
|
||||
private boolean mKeepFlipping = false;
|
||||
private static final String TAG = "ViewFlipper";
|
||||
private static final boolean LOGD = true;
|
||||
|
||||
private static final int DEFAULT_INTERVAL = 3000;
|
||||
|
||||
private int mFlipInterval = DEFAULT_INTERVAL;
|
||||
private boolean mAutoStart = false;
|
||||
|
||||
private boolean mRunning = false;
|
||||
private boolean mStarted = false;
|
||||
private boolean mVisible = false;
|
||||
private boolean mUserPresent = true;
|
||||
|
||||
public ViewFlipper(Context context) {
|
||||
super(context);
|
||||
@@ -44,14 +59,62 @@ public class ViewFlipper extends ViewAnimator {
|
||||
|
||||
TypedArray a = context.obtainStyledAttributes(attrs,
|
||||
com.android.internal.R.styleable.ViewFlipper);
|
||||
mFlipInterval = a.getInt(com.android.internal.R.styleable.ViewFlipper_flipInterval,
|
||||
3000);
|
||||
mFlipInterval = a.getInt(
|
||||
com.android.internal.R.styleable.ViewFlipper_flipInterval, DEFAULT_INTERVAL);
|
||||
mAutoStart = a.getBoolean(
|
||||
com.android.internal.R.styleable.ViewFlipper_autoStart, false);
|
||||
a.recycle();
|
||||
}
|
||||
|
||||
private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
|
||||
@Override
|
||||
public void onReceive(Context context, Intent intent) {
|
||||
final String action = intent.getAction();
|
||||
if (Intent.ACTION_SCREEN_OFF.equals(action)) {
|
||||
mUserPresent = false;
|
||||
updateRunning();
|
||||
} else if (Intent.ACTION_USER_PRESENT.equals(action)) {
|
||||
mUserPresent = true;
|
||||
updateRunning();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@Override
|
||||
protected void onAttachedToWindow() {
|
||||
super.onAttachedToWindow();
|
||||
|
||||
// Listen for broadcasts related to user-presence
|
||||
final IntentFilter filter = new IntentFilter();
|
||||
filter.addAction(Intent.ACTION_SCREEN_OFF);
|
||||
filter.addAction(Intent.ACTION_USER_PRESENT);
|
||||
getContext().registerReceiver(mReceiver, filter);
|
||||
|
||||
if (mAutoStart) {
|
||||
// Automatically start when requested
|
||||
startFlipping();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onDetachedFromWindow() {
|
||||
super.onDetachedFromWindow();
|
||||
mVisible = false;
|
||||
|
||||
getContext().unregisterReceiver(mReceiver);
|
||||
updateRunning();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onWindowVisibilityChanged(int visibility) {
|
||||
super.onWindowVisibilityChanged(visibility);
|
||||
mVisible = visibility == VISIBLE;
|
||||
updateRunning();
|
||||
}
|
||||
|
||||
/**
|
||||
* How long to wait before flipping to the next view
|
||||
*
|
||||
*
|
||||
* @param milliseconds
|
||||
* time in milliseconds
|
||||
*/
|
||||
@@ -64,26 +127,61 @@ public class ViewFlipper extends ViewAnimator {
|
||||
* Start a timer to cycle through child views
|
||||
*/
|
||||
public void startFlipping() {
|
||||
if (!mKeepFlipping) {
|
||||
mKeepFlipping = true;
|
||||
showOnly(mWhichChild);
|
||||
Message msg = mHandler.obtainMessage(FLIP_MSG);
|
||||
mHandler.sendMessageDelayed(msg, mFlipInterval);
|
||||
}
|
||||
mStarted = true;
|
||||
updateRunning();
|
||||
}
|
||||
|
||||
/**
|
||||
* No more flips
|
||||
*/
|
||||
public void stopFlipping() {
|
||||
mKeepFlipping = false;
|
||||
mStarted = false;
|
||||
updateRunning();
|
||||
}
|
||||
|
||||
/**
|
||||
* Internal method to start or stop dispatching flip {@link Message} based
|
||||
* on {@link #mRunning} and {@link #mVisible} state.
|
||||
*/
|
||||
private void updateRunning() {
|
||||
boolean running = mVisible && mStarted && mUserPresent;
|
||||
if (running != mRunning) {
|
||||
if (running) {
|
||||
showOnly(mWhichChild);
|
||||
Message msg = mHandler.obtainMessage(FLIP_MSG);
|
||||
mHandler.sendMessageDelayed(msg, mFlipInterval);
|
||||
} else {
|
||||
mHandler.removeMessages(FLIP_MSG);
|
||||
}
|
||||
mRunning = running;
|
||||
}
|
||||
if (LOGD) {
|
||||
Log.d(TAG, "updateRunning() mVisible=" + mVisible + ", mStarted=" + mStarted
|
||||
+ ", mUserPresent=" + mUserPresent + ", mRunning=" + mRunning);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the child views are flipping.
|
||||
*/
|
||||
public boolean isFlipping() {
|
||||
return mKeepFlipping;
|
||||
return mStarted;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set if this view automatically calls {@link #startFlipping()} when it
|
||||
* becomes attached to a window.
|
||||
*/
|
||||
public void setAutoStart(boolean autoStart) {
|
||||
mAutoStart = autoStart;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if this view automatically calls {@link #startFlipping()}
|
||||
* when it becomes attached to a window.
|
||||
*/
|
||||
public boolean isAutoStart() {
|
||||
return mAutoStart;
|
||||
}
|
||||
|
||||
private final int FLIP_MSG = 1;
|
||||
@@ -92,7 +190,7 @@ public class ViewFlipper extends ViewAnimator {
|
||||
@Override
|
||||
public void handleMessage(Message msg) {
|
||||
if (msg.what == FLIP_MSG) {
|
||||
if (mKeepFlipping) {
|
||||
if (mRunning) {
|
||||
showNext();
|
||||
msg = obtainMessage(FLIP_MSG);
|
||||
sendMessageDelayed(msg, mFlipInterval);
|
||||
|
||||
@@ -2138,6 +2138,8 @@
|
||||
</declare-styleable>
|
||||
<declare-styleable name="ViewFlipper">
|
||||
<attr name="flipInterval" format="integer" min="0" />
|
||||
<!-- When true, automatically start animating -->
|
||||
<attr name="autoStart" format="boolean" />
|
||||
</declare-styleable>
|
||||
<declare-styleable name="ViewSwitcher">
|
||||
</declare-styleable>
|
||||
|
||||
@@ -1201,8 +1201,8 @@
|
||||
<public type="attr" name="quickContactBadgeStyleSmallWindowSmall" />
|
||||
<public type="attr" name="quickContactBadgeStyleSmallWindowMedium" />
|
||||
<public type="attr" name="quickContactBadgeStyleSmallWindowLarge" />
|
||||
|
||||
<public type="attr" name="wallpaperAuthor" />
|
||||
<public type="attr" name="wallpaperDescription" />
|
||||
<public type="attr" name="autoStart" />
|
||||
|
||||
</resources>
|
||||
|
||||
Reference in New Issue
Block a user